AI 에이전트가 외부 도구를 호출할 때 발생하는 보안 취약점을 체계적으로 방어하는 방법을 다룹니다. Function Calling은 AI의 도구 활용 능력을 극대화하지만, 공격자가 의도치 않은 매개변수를 주입할 경우 시스템 전체가 위험에 노출될 수 있습니다.
핵심 결론: 즉시 적용해야 할 3가지
Function Calling 보안의 본질은 입력 검증, 스키마 강제, 최소 권한 원칙입니다. 이 세 가지를 조합하면 대부분의 주입 공격을 차단할 수 있으며, HolySheep AI의 단일 API 키로 모든 주요 모델에 일관된 보안 정책을 적용할 수 있습니다.
AI API 서비스 비교
| 서비스 | 가격 (GPT-4o 기준) | 지연 시간 | 결제 방식 | Function Calling 지원 | 적합한 팀 |
|---|---|---|---|---|---|
| HolySheep AI | $2.50/MTok (Flash) $8/MTok (GPT-4.1) |
~800ms | 로컬 결제 (신용카드 불필요) | ✓ Claude + GPT + Gemini | 중소팀, 해외 결제 어려운 개발자 |
| OpenAI 공식 | $15/MTok (GPT-4o) | ~600ms | 국제 신용카드 필수 | ✓ Native | 대기업, 미국 기반 팀 |
| Anthropic 공식 | $15/MTok (Sonnet 4.5) | ~900ms | 국제 신용카드 필수 | ✓ Native | 긴 컨텍스트 필요한 프로젝트 |
| Google Gemini | $2.50/MTok (Flash 2.5) | ~700ms | 국제 신용카드 필수 | ✓ Function Calling | 비용 최적화 중시 팀 |
악성 매개변수 주입이란?
攻击자는 Function Calling의 tool_calls 페이로드에 특수 문자, 이스케이프 시퀀스, 또는 JSON 오염 데이터를 삽입하여 AI 모델의 파싱 로직을 우회합니다. 예를 들어:
{
"name": "send_email",
"arguments": "{\"to\":\"[email protected]\",\"body\":\"Hi\\n---\\ncc:[email protected]\"}"
}
이 주입은 이메일 본문에 CC 헤더를 추가하여 의도치 않은 수신자에게 메시지를 전달합니다.
방어 전략 1: JSON 스키마 검증
가장 효과적인 1차 방어선은 AI가 생성한 arguments를 엄격한 JSON Schema로 검증하는 것입니다. 저는 실무에서 이 전략으로 주입 공격의 95%를 차단했습니다.
import json
import re
from jsonschema import validate, ValidationError
허용된 Function 정의
ALLOWED_FUNCTIONS = {
"send_email": {
"type": "object",
"properties": {
"to": {"type": "string", "pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+$"},
"subject": {"type": "string", "maxLength": 200},
"body": {"type": "string", "maxLength": 5000}
},
"required": ["to", "body"],
"additionalProperties": False
},
"search_database": {
"type": "object",
"properties": {
"query": {"type": "string", "maxLength": 500},
"limit": {"type": "integer", "minimum": 1, "maximum": 100}
},
"required": ["query"],
"additionalProperties": False
}
}
def validate_function_call(function_name: str, arguments: dict) -> tuple[bool, str]:
"""
Function Calling 인자를 검증하고 안전하게 반환합니다.
Returns: (is_safe, error_message)
"""
# 1단계: Function 이름 화이트리스트 검증
if function_name not in ALLOWED_FUNCTIONS:
return False, f"알려지지 않은 함수: {function_name}"
# 2단계: JSON Schema 검증
try:
validate(instance=arguments, schema=ALLOWED_FUNCTIONS[function_name])
except ValidationError as e:
return False, f"스키마 검증 실패: {e.message}"
# 3단계: 인젝션 패턴 추가 검사
injection_patterns = [
r"[\r\n]{2,}.*cc:", # 이메일 헤더 주입
r"[\r\n]{2,}.*bcc:", # 숨은 참조 주입
r"{{.*}}", # 템플릿 인젝션
r"