LLM 프롬프트 유출 방지를 위한 다중 리전 카나리 트랩 구축
요약
LLM 시스템 프롬프트 유출을 방지하기 위해 패턴 매칭 대신 카나리 토큰(Canary Token)을 활용한 탐지 기법을 소개합니다. Redis를 이용해 다중 리전 환경에서 상태를 동기화하고, 수동적 탐지와 센티넬 변형 방식을 통해 프롬프트 주입 공격에 대응하는 실전 가이드를 제공합니다.
핵심 포인트
- 패턴 매칭의 높은 오탐률을 해결하기 위해 엔트로피 기반의 카나리 토큰 활용
- Redis를 사용하여 다중 인스턴스 및 복제본 간 카나리 상태 동기화
- 시스템 프롬프트 유출 탐지를 위한 수동적 카나리 구현
- 모델 지시사항 탈취를 감지하기 위한 센티넬(Sentinel) 변형 방식 적용
- 탐지 즉시 실시간 알림이 전달되는 모니터링 체계 구축의 중요성
시스템 프롬프트가 유출될 것입니다. '할지도 모른다'는 이야기가 아닙니다. 시스템 프롬프트를 훔칠 가치가 있는 모든 LLM 앱은 결국 모델에게 그 내용을 단어 그대로 반복하도록 속이는 공격자를 만나게 됩니다. 필터로는 막을 수 없으니, 시도하는 것을 멈추십시오. 대신, 그것이 발생하는 순간 알려주는 트랩을 구축하십시오.
그것이 바로 카나리 토큰(canary token)입니다. 모델이 반복해서는 안 되는 곳에 심어둔 임의 문자열이며, 출구에서 스캔됩니다. 하나의 문자열, 하나의 부분 문자열 확인으로 구성되어 있어 오탐률(false positive)이 없습니다. 아이디어만 듣고 고개를 끄덕이는 대신, 실제로 실행 중인 앱에 이것을 연결하는 방법을 소개합니다.
정규 표현식 필터가 충분하지 않은 이유
대부분의 팀은 먼저 패턴 매칭(pattern matching)부터 시도합니다. '이전 지침 무시'처럼 보이는 모든 것을 차단하고, 의심스러운 문구를 플래그 지정하며, 분류기(classifier)의 신뢰 임계값(confidence threshold)을 조정합니다. 이 모든 것이 노이즈에 당신을 빠뜨립니다. 왜냐하면 호기심 많은 사용자들이 '이전 지침 무시'를 끊임없이 입력하고 그것에는 아무 의미가 없기 때문입니다.
카나리는 패턴 매칭 대신 엔트로피(entropy)를 통해 이러한 복잡한 문제를 우회합니다. 임의의 16바이트를 가져오면, 그 정확한 문자열이 합법적인 트래픽에 나타날 확률은 제로에 가깝습니다. 조정할 패턴도 없고, 돌봐야 할 임계값도 없습니다. 문자열은 오거나 아니거나입니다.
pip install python-dotenv redis
여기서 Redis를 추가하는 이유는 한 가지입니다. 카나리 상태(canary state)는 재시작 후에도 살아남고 복제본(replicas) 간에 동기화되어야 하기 때문입니다. 단일 프로세스의 메모리에 존재하는 카나리는 인스턴스를 하나 이상으로 확장하는 순간 쓸모가 없어집니다.
레이어 1: 심고 스캔하기
LLM01, 프롬프트 주입(prompt injection)에 대해 OWASP가 권장하는 기본 사항부터 시작합니다. 시스템 프롬프트에 합성 토큰을 떨어뜨리고, 모든 응답에서 이를 스캔합니다.
import secrets
import redis
...
Redis는 여기서 지루하지만 핵심적인 작업을 수행합니다. 모든 복제본이 동일한 카나리 상태를 읽기 때문에, 히트(hit)가 발생한 후 토큰을 순환시키면 단지 해당 인스턴스에서만 순환되는 것이 아니라 모든 곳에서 순환됩니다.
레이어 2: 추가하고 제거하는 변형 (append-and-strip variant)
원문 기사에서 다루지 않는 부분이지만, 추가적인 코드를 작성할 만한 가치가 있는 내용입니다. OWASP의 LLM Top 10 트래커는 수동적 탐지 (passive detection)보다 더 엄격한 두 번째 카나리 패턴을 기록하고 있습니다. 바로 모델에게 모든 응답의 끝에 특정 토큰을 추가하도록 지시한 다음, 응답이 사용자에게 도달하기 전에 해당 토큰을 제거 (strip)하는 방식입니다.
STRIP_CANARY = new_canary("sentinel")
def build_system_prompt(base_prompt: str) -> str:
...
수동적 카나리 (passive canary)는 시스템 프롬프트가 유출되었을 때를 알려줍니다. 반면 센티넬 (sentinel) 변형 방식은 모델이 기본적인 지시 사항을 아예 따르지 않게 된 시점을 알려줍니다. 이는 표시된 텍스트에 전혀 손을 대지 않고도 동작을 탈취하는 인젝션 (injection) 공격에 대해 더 넓은 범위의 경보 장치 (tripwire) 역할을 합니다. 실패 모드는 다르지만, 기법은 동일합니다.
레이어 3: 진심을 담아 알림 보내기
아무도 모니터링하지 않는 로그 파일에만 기록되는 카나리 탐지는 이미 실패한 카나리나 다름없습니다. 사람에게 페이지 (page)를 보내는 시스템에 연결하세요.
import json
import logging
import time
...
일반 텍스트 로깅 (plain-text logging)보다 구조화된 JSON (Structured JSON)을 사용하는 것은 보기보다 훨씬 중요합니다. 실제 추출 공격이 진행 중인 새벽 2시에 자유 형식의 로그 라인에서 타임스탬프를 검색 (grepping)하고 있다면, 당신은 이미 여유가 없는 10분을 허비한 것입니다.
사람들을 괴롭히는 주의사항 (Gotchas)
여기서 상수 시간 비교 (Constant-time comparison)를 사용하는 것은 적절하지 않습니다. 인증 (auth) 관련 작업을 해보셨다면, 문자열 비교 시 secrets.compare_digest를 사용하는 것이 습관처럼 되어 있을 것입니다. 카나리 스캐닝에서는 이를 건너뛰세요. 해당 함수는 공격자가 입력을 제어하고 응답 시간을 측정하여 비밀 비교를 시도하는 타이밍 공격 (timing attacks)을 막기 위해 존재합니다. 카나리 스캔은 공격자가 동일한 방식으로 시간을 측정하여 탐색할 수 없는 모델 출력에 대한 단순한 봉쇄 확인 (containment check)입니다. 이를 사용하면 해당되지 않는 위협 모델에 대해 불필요한 지연 시간 (latency)만 추가하게 됩니다.
Redis TTL (Time To Live)이 카나리(canary)를 조용히 삼켜버릴 수 있습니다. 관련 없는 이유로(예: 캐시 제거 정책(cache eviction policy)을 재사용하는 경우 등) 토큰 키에 만료 시간을 설정하면, 세션 중간에 카나리가 사라져 current_canary가 None을 반환하고 scan_output이 아무것도 확인하지 않은 채 조용히 중단됩니다. 카나리 키에는 TTL을 설정하지 않거나, 분(minutes) 단위가 아닌 일(days) 단위로 측정된 TTL을 설정하십시오.
센티넬 패턴(sentinel pattern)에는 자체적인 실패 예산(failure budget)이 필요합니다. 모델이
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기