반응형
2025년, 조용히 인터넷이 바뀌었어요.
HUMAN Security가 1경(10^15) 개 이상의 디지털 상호작용을 분석한 결과:
2025년 트래픽 증가율:
AI 에이전트 브라우저 트래픽: +7,851%
AI 봇 전체: +187%
사람: +3.1%
자동화 트래픽 성장속도 = 사람의 8배
Cloudflare CEO 매튜 프린스가 2026년 3월 SXSW에서 한 말:
"2027년이면 봇 트래픽이 사람 트래픽을 추월한다.
COVID 때처럼 반짝 스파이크가 아니다.
멈출 기미가 없다."
2024년 이미 자동화 트래픽이 전체 웹 트래픽의 51%를 넘겼어요. 인터넷 역사상 처음이에요.
문제는 대부분의 서버와 API가 여전히 사람 트래픽 기준으로 설계되어 있다는 거예요.
무엇이 달라졌나
예전 봇 vs 지금 AI 에이전트
예전 봇:
→ 정해진 패턴으로 반복 요청
→ User-Agent 보면 바로 티남
→ robots.txt 대부분 준수
→ 주로 크롤링/스크래핑
지금 AI 에이전트:
→ 사람처럼 브라우저 열고 클릭
→ User-Agent 위장 가능
→ robots.txt 13% 무시
→ 쇼핑, 예약, 폼 제출, 결제까지
진짜 무서운 숫자:
악성 자동화 vs 정상 자동화의 행동 차이: 0.5%
즉, 합법적인 AI 쇼핑 에이전트와
자동화 사기 봇의 행동이 99.5% 같음
실제로 벌어지는 일
이커머스:
→ 고객의 AI 에이전트가 빠르게 상품 탐색 + 결제
→ 사기봇도 똑같이 빠르게 탐색 + 결제 시도
→ 구분 불가
계정 탈취:
→ 2025년 조직당 평균 402,000건의 로그인 후 계정 침해 시도
→ 전년 대비 4배 증가
스크래핑:
→ 전체 사이트 방문의 약 20%가 스크래핑 시도
→ 2022년 대비 2배
AWS/Azure 청구서:
→ AI 크롤러에게 콘텐츠 서빙하느라 예상치 못한 폭탄 청구
기존 방어 전략이 왜 안 통하나
문제 1 — IP 기반 Rate Limiting
기존 방어:
"IP당 분당 100 요청 초과 시 차단"
AI 에이전트 공격:
→ IP 1,000개에 분산 배치
→ 각 IP는 분당 10 요청만 전송
→ 한 IP도 임계값 미달
→ 총합: 분당 10,000 요청
결과: 차단 안 됨
문제 2 — User-Agent 필터링
기존 User-Agent 허용 목록:
"Googlebot, Bingbot은 허용"
현실:
→ AI 에이전트가 Chrome/Safari 위장 가능
→ 정상 브라우저와 구분 불가
→ User-Agent 필터링 무의미
문제 3 — CAPTCHA
GPT-5.4, Claude Opus 4.7 비전 능력:
→ 이미지 인식 능력이 사람과 동등
→ reCAPTCHA v2 통과율 95%+
→ CAPTCHA는 AI 에이전트에 무력화
문제 4 — 요청 수 기반 API Rate Limiting
기존:
"API 키당 분당 100 요청"
AI 에이전트 요청의 실제 비용 차이:
→ 간단한 조회: 50 토큰
→ 복잡한 추론: 50,000 토큰
→ 같은 "1 요청"이지만 비용은 1,000배 차이
결과:
→ 가벼운 요청 1,000개 허용 = 문제없음
→ 무거운 요청 100개 허용 = 서버 폭발
→ "요청 수"는 의미 없는 지표
2026년 실전 방어 전략
전략 1 — 토큰 기반 Rate Limiting
요청 수가 아니라 실제 리소스 소비를 기준으로 제한해요.
from fastapi import FastAPI, HTTPException, Request
from collections import defaultdict
import time
app = FastAPI()
# 토큰 버킷 구현
class TokenBucket:
def __init__(self, capacity: int, refill_rate: float):
self.capacity = capacity # 최대 토큰 수
self.tokens = capacity # 현재 토큰 수
self.refill_rate = refill_rate # 초당 보충 토큰
self.last_refill = time.time()
def consume(self, tokens: int) -> bool:
now = time.time()
elapsed = now - self.last_refill
# 시간 경과에 따라 토큰 보충
self.tokens = min(
self.capacity,
self.tokens + elapsed * self.refill_rate
)
self.last_refill = now
if self.tokens >= tokens:
self.tokens -= tokens
return True # 허용
return False # 거부
# API 키별 버킷 관리
buckets = defaultdict(lambda: TokenBucket(
capacity=100_000, # 최대 10만 토큰
refill_rate=1_000 # 초당 1,000 토큰 보충
))
@app.post("/api/llm")
async def llm_endpoint(request: Request, payload: dict):
api_key = request.headers.get("X-API-Key")
if not api_key:
raise HTTPException(status_code=401)
# 요청에서 예상 토큰 수 추정
estimated_tokens = estimate_tokens(payload.get("prompt", ""))
bucket = buckets[api_key]
if not bucket.consume(estimated_tokens):
raise HTTPException(
status_code=429,
headers={
"X-RateLimit-Tokens-Remaining": str(int(bucket.tokens)),
"X-RateLimit-Reset": "60",
"Retry-After": "60"
},
detail="토큰 한도 초과"
)
# 실제 처리
response = await process_llm_request(payload)
# 실제 사용 토큰을 헤더로 반환 (에이전트가 자가 조절 가능)
actual_tokens = response.usage.total_tokens
return {
"result": response.content,
"tokens_used": actual_tokens
}
def estimate_tokens(text: str) -> int:
# 대략 4자 = 1토큰
return max(len(text) // 4, 1)
계층형 Rate Limit:
# 짧은 기간 + 긴 기간 조합
RATE_LIMITS = {
"free": {
"per_minute": 10_000, # 분당 1만 토큰
"per_day": 1_000_000, # 일당 100만 토큰
},
"pro": {
"per_minute": 100_000,
"per_day": 10_000_000,
},
"enterprise": {
"per_minute": 1_000_000,
"per_day": 100_000_000,
}
}
전략 2 — 에이전트 신원 검증
이제 API를 두 가지로 분리해서 관리해야 해요.
from enum import Enum
from dataclasses import dataclass
class ClientType(Enum):
HUMAN = "human"
AGENT = "agent"
CRAWLER = "crawler"
UNKNOWN = "unknown"
@dataclass
class ClientProfile:
type: ClientType
api_key: str
agent_id: str | None # 에이전트 식별자
owner_id: str | None # 에이전트 소유 사용자
def classify_client(request: Request) -> ClientProfile:
ua = request.headers.get("User-Agent", "")
api_key = request.headers.get("X-API-Key", "")
# 에이전트 자가 신고 헤더 (새 표준)
agent_id = request.headers.get("X-Agent-ID")
owner_id = request.headers.get("X-Agent-Owner")
# 알려진 AI 에이전트 패턴
agent_patterns = [
"claude-code", "openai-codex", "cursor",
"python-httpx", "python-requests",
"anthropic-sdk", "openai-sdk"
]
if agent_id:
return ClientProfile(
type=ClientType.AGENT,
api_key=api_key,
agent_id=agent_id,
owner_id=owner_id
)
elif any(p in ua.lower() for p in agent_patterns):
return ClientProfile(
type=ClientType.AGENT,
api_key=api_key,
agent_id=None,
owner_id=None
)
else:
return ClientProfile(
type=ClientType.HUMAN,
api_key=api_key,
agent_id=None,
owner_id=None
)
# 클라이언트 타입에 따라 다른 정책 적용
async def apply_policy(profile: ClientProfile, request: Request):
if profile.type == ClientType.AGENT:
# 에이전트: 토큰 기반 제한 + 비용 추적
return await agent_policy(profile, request)
elif profile.type == ClientType.HUMAN:
# 사람: 요청 수 기반 제한
return await human_policy(profile, request)
else:
# 미확인: 보수적 제한
return await unknown_policy(profile, request)
전략 3 — 행동 기반 이상 탐지
0.5% 차이밖에 없는 정상/악성 에이전트를 구분하는 방법이에요.
import hashlib
from collections import deque
class AgentBehaviorTracker:
def __init__(self, window_size: int = 100):
self.window_size = window_size
# API 키별 최근 요청 패턴 추적
self.request_history = defaultdict(lambda: deque(maxlen=window_size))
def record(self, api_key: str, endpoint: str, tokens: int, latency_ms: float):
self.request_history[api_key].append({
"endpoint": endpoint,
"tokens": tokens,
"latency_ms": latency_ms,
"timestamp": time.time()
})
def is_anomalous(self, api_key: str) -> dict:
history = list(self.request_history[api_key])
if len(history) < 10:
return {"anomalous": False}
recent = history[-10:]
# 이상 패턴 감지
checks = {
# 1. 동일 엔드포인트 반복 (루프 감지)
"loop": len(set(r["endpoint"] for r in recent)) == 1,
# 2. 토큰 급증 (폭주 에이전트)
"token_spike": (
recent[-1]["tokens"] >
sum(r["tokens"] for r in recent[:-1]) / len(recent[:-1]) * 10
),
# 3. 비정상적으로 빠른 요청 (밀리초 단위)
"too_fast": all(
r["latency_ms"] < 10 for r in recent
),
# 4. 비용 폭발 (최근 10분간 급증)
"cost_explosion": self._check_cost_explosion(api_key)
}
is_anomalous = any(checks.values())
return {
"anomalous": is_anomalous,
"reasons": [k for k, v in checks.items() if v]
}
def _check_cost_explosion(self, api_key: str) -> bool:
history = list(self.request_history[api_key])
if len(history) < 20:
return False
# 앞 절반 vs 뒷 절반 토큰 사용량 비교
mid = len(history) // 2
first_half_avg = sum(r["tokens"] for r in history[:mid]) / mid
second_half_avg = sum(r["tokens"] for r in history[mid:]) / mid
return second_half_avg > first_half_avg * 5 # 5배 초과 시 이상
전략 4 — robots.txt → llms.txt
robots.txt는 이미 13%의 AI 봇이 무시해요. 새로운 표준이 등장했어요.
# robots.txt (기존)
User-agent: *
Disallow: /private/
Crawl-delay: 10
# llms.txt (새 표준 — AI 에이전트 전용)
# 위치: https://yoursite.com/llms.txt
# AI 훈련 크롤러 허용 여부
AI-Training: disallowed
# AI 에이전트 접근 정책
AI-Agent-Access: allowed
AI-Agent-Rate-Limit: 1000 tokens/minute
AI-Agent-Contact: api@yoursite.com
# 허용 에이전트
Allow-Agent: Claude/*
Allow-Agent: GPT/*
Allow-Agent: Gemini/*
# 차단 에이전트
Disallow-Agent: *DataScraper*
Disallow-Agent: *TrainingCrawler*
전략 5 — 인프라 비용 방어
AI 크롤러가 서버 비용을 올리는 걸 막아야 해요.
# Nginx 설정
# AI 크롤러 User-Agent 감지 후 차별화 처리
geo $ai_traffic {
default 0;
# 알려진 AI 크롤러 IP 대역
66.249.0.0/16 1; # Googlebot
157.55.0.0/16 1; # Bingbot
}
map $http_user_agent $is_ai_agent {
default 0;
~*"ClaudeBot" 1;
~*"GPTBot" 1;
~*"anthropic-ai" 1;
~*"PerplexityBot" 1;
~*"Python-httpx" 1;
}
server {
# AI 에이전트 전용 제한
limit_req_zone $binary_remote_addr
zone=ai_agents:10m rate=10r/m;
location / {
if ($is_ai_agent) {
limit_req zone=ai_agents burst=5;
# 정적 캐시 서빙 (DB 히트 없음)
add_header X-Served-By "cache";
}
}
# 크롤러 전용 엔드포인트
# 비용 없는 정적 콘텐츠만 서빙
location /ai-feed/ {
alias /var/www/static-feed/;
# 여기서만 크롤러 허용
}
}
지금 당장 해야 할 것
즉시 (이번 주):
□ 서버 로그에서 AI 에이전트 트래픽 비중 측정
□ API에 X-Agent-ID 헤더 지원 추가
□ llms.txt 파일 작성해서 배포
단기 (이번 달):
□ 요청 수 → 토큰 수 기반 Rate Limit 전환
□ 에이전트 행동 이상 탐지 모니터링 추가
□ AI 크롤러 전용 정적 캐시 레이어 구축
중기 (다음 분기):
□ 에이전트 신원 검증 시스템 구축
□ 인간 트래픽 vs 에이전트 트래픽 별도 analytics 파이프라인
□ 에이전트 전용 API 티어 설계
반응형
'AI Development' 카테고리의 다른 글
| markitdown 완전 가이드 — PDF, Word, PPT를 LLM이 읽는 형식으로 자동 변환 (0) | 2026.04.21 |
|---|---|
| Gemini CLI 가이드 — Claude Code 대신 $0에 쓰는 법 (1) | 2026.04.21 |
| Spec-Driven Development — Vibe Coding 다음 단계, AI 에이전트 개발 방법론 (1) | 2026.04.17 |
| OpenAI Codex 대규모 업데이트 — 컴퓨터를 대신 써주는 AI 코딩 도구 (0) | 2026.04.17 |
| OpenAI Agents SDK 대규모 업데이트 — Claude Code Routines 나온 지 3일 만에 맞불 (2) | 2026.04.17 |