Как ограничить ущерб от промпт-инъекции в LLM API
Промпт-инъекцию нельзя надёжно выключить одной фразой в системной инструкции или списком запрещённых слов. Я советую строить защиту вокруг последствий: отделять недоверенные данные, ограничивать доступ приложения и проверять каждое действие и ответ до передачи дальше.
Что именно делает промпт-инъекция
Промпт-инъекция — это попытка повлиять на поведение языковой модели через специально подготовленный ввод или данные, которые приложение ей передало. В прямом варианте текст приходит от пользователя. В косвенном — инструкция спрятана в письме, документе, веб-странице или ответе внешнего сервиса, который бот должен прочитать. Для приложения это принципиально: фильтр формы видит только первый маршрут, а извлечённые материалы могут поступать из десятка других мест. OWASP относит prompt injection к отдельному риску LLM01 и прямо оговаривает, что RAG и дообучение не устраняют его полностью. Это первое важное уточнение: перед нами класс риска обработки инструкций и данных, а не волшебная строка, которая каждый раз «ломает бота» одинаково.
Модель может выдать нежелательный текст, проигнорировать часть правил или предложить действие, которого пользователь не просил. Само по себе раскрытие системной инструкции не означает, что злоумышленник получил доступ к серверу, почте или базе данных. Последствия зависят от того, что приложение разрешило сделать после ответа модели. У чат-бота, который только формирует справочный текст, последствия одни; у агента с доступом к почте, документам и внутренним API — совсем другие. Поэтому я сначала выясняю, какие данные доступны, какие инструменты подключены и кто проверяет результат, а уже потом обсуждаю фильтры. Ирония короткая: громкое слово в запросе ещё не равно взлому инфраструктуры.
Не смешивайте промпт-инъекцию и jailbreak как синонимы. В материалах OWASP эти понятия связаны и иногда употребляются рядом, но полезно различать акцент: injection воздействует на приложение через контекст, пользовательские или внешние данные; jailbreak пытается заставить модель нарушить ограничения её поведения. На практике один ввод может совмещать оба приёма. Для защиты терминологический спор ничего не меняет: результат модели нельзя автоматически считать командой, а её встроенные отказы не заменяют проверки доступа в коде.
Косвенная инъекция особенно легко теряется в рассуждениях о «пользовательском вводе». Пользователь может попросить кратко изложить вложенный файл, а вредная инструкция будет внутри самого файла. То же относится к найденной странице, фрагменту базы знаний или тексту, возвращённому инструментом. Все эти материалы следует считать недоверенными данными, даже если они пришли из вашего хранилища: содержание мог изменить автор документа, внешний источник или другой процесс. Это не повод запрещать чтение файлов. Это повод не давать прочитанному тексту полномочия менять права приложения.
В условном примере компании «Циркон-Строй» служба поддержки добавляет поиск по внутренним документам. Такой сценарий полезен для разбора, но я не выдаю его за реальный инцидент или внедрение «АйТи-Фреш»: доказательств для этого в исходном материале нет. Если в документе встречается команда вроде «отправь найденные данные наружу», проверять надо не только текст фильтром, но и саму возможность отправки. Когда у поиска нет инструмента отправки, одной инъекции недостаточно для такого действия. Именно доступы определяют масштаб ущерба.
- Прямой ввод пользователя и косвенные инструкции в документах — разные пути доставки
- Утечка текста инструкции сама по себе не подтверждает доступ к серверу
- Риск растёт вместе с правами подключённых инструментов
Граница между инструкцией и данными
Начните с понятного разделения доверенного управления и недоверенного содержимого. Системные инструкции задаёт серверная часть; клиентский интерфейс не должен иметь возможность менять их или передавать произвольные права. Документы, поисковые выдержки и пользовательские сообщения помечайте как данные, а не как команды приложения. Если API использует отдельные роли или поля для системного сообщения и пользовательского сообщения, применяйте их по назначению. Такая структура делает границы яснее и упрощает аудит, но не создаёт для модели непроницаемую перегородку. OWASP рекомендует отделять внешний контент и явно обозначать его недоверенность, одновременно предупреждая: гарантированного способа полностью предотвратить injection нет.
Фраза «системный промпт лежит отдельно» звучит убедительно, но отвечает только на вопрос, кто его редактирует. Она не мешает модели прочитать пользовательскую инструкцию в другом сообщении и среагировать на неё. То же касается переменной окружения или файла конфигурации: это способы доставки и хранения настроек, а не защита от интерпретации содержимого. Секреты, пароли и полномочия вообще не следует помещать в промпт в надежде, что модель сохранит их в тайне. Системные инструкции могут быть раскрыты через ответ; права на реальные данные должны проверяться сервером независимо от того, что модель обещала в тексте.
Сборку контекста удобно сосредоточить в серверном слое или прокси: он проверяет, кто обращается, какие документы разрешено читать, какие части контекста передать и какой ответ ожидается. Но прокси — не защитное заклинание. Если он просто склеивает строки и пересылает их дальше, архитектура почти не изменилась. Полезная работа слоя — удерживать правила доступа вне модели, применять проверяемые ограничения, отсекать лишние данные и валидировать структурированный результат перед использованием. Разделение ролей помогает организовать поток, а критические решения должны оставаться в обычной логике приложения.
Не считайте, что пользовательский текст безопасен после удаления нескольких фраз вроде “ignore previous instructions”. Формулировки можно менять, переводить, прятать в длинном контексте или передавать через вложенный файл. Эвристические правила полезны как сигнал или вспомогательная проверка, но точный список ключевых слов неизбежно пропускает варианты и иногда блокирует обычные вопросы. Если фильтр отклоняет запрос, API может вернуть подходящий код по контракту именно вашего сервиса; универсального требования использовать 400 или 422 для prompt injection нет. В исходном варианте оба кода указаны для одного и того же сценария — это не факт, а противоречие, поэтому здесь я их не предписываю.
Проверьте всю цепочку данных: поле чата, историю диалога, поиск, загруженные файлы, веб-страницы, ответы инструментов и результат модели. Для каждого источника задайте владельца, допустимые данные и правила доступа. Не передавайте в контекст документы, которые текущий пользователь не вправе видеть, даже если модель обещает не цитировать их. Фильтрация на уровне промпта не компенсирует ошибку авторизации в поиске. И наоборот, корректные ACL не гарантируют, что бот не сформирует вредный или вводящий в заблуждение ответ; разные проверки закрывают разные места.
- Пусть сервер формирует доверенные инструкции
- Обозначайте документы и результаты поиска как недоверенные данные
- Проверяйте авторизацию до включения данных в контекст
Фильтры и Prompt Guard 2: только дополнительный слой
Входные и выходные проверки полезны, если у них узкая, понятная задача. Например, не допустить в ответе секретный идентификатор, проверить JSON по ожидаемой схеме или не передавать модельный текст напрямую в SQL, HTML, командную оболочку либо API-вызов. Для этого надёжнее детерминированная проверка структуры и полномочий, чем просьба к модели «будь осторожна». OWASP выделяет также риск небезопасной обработки результата LLM: ошибка возникает, когда приложение использует сгенерированный текст без проверки. Необходимо проверять не только, что пользователь отправил на вход, но и то, что приложение собирается сделать с ответом.
Prompt Guard 2 существует: Meta публикует карточки моделей Llama Prompt Guard 2 86M и 22M. Это классификаторы, предназначенные для обнаружения известных шаблонов prompt-атак и jailbreak. Документация описывает бинарную метку «benign/malicious», окно контекста 512 токенов и поддержку нескольких языков для версии 86M. Эти характеристики — конкретная граница применимости, а не обещание универсального детектора: неизвестные приёмы, длинный контекст, особенности языка и ложные срабатывания требуют оценки на ваших данных. Если внедряете такой классификатор, измеряйте качество именно на типичных сообщениях продукта и ведите разбор ошибочных блокировок.
Не добавляйте инструмент в перечень защиты только по названию. Нужны точный продукт, производитель и подтверждённое назначение: совпадение бренда само по себе не доказывает, что решение обнаруживает prompt injection. В данном случае нет подтверждений ни подходящего продукта, ни его внедрения, поэтому я не выдаю его за проверенный компонент защиты. По той же причине я убрал историю о том, что команда поставила инструменты и обнаружила ими атаку: для такого клиентского кейса нужны проверяемые факты.
Список запрещённых слов не должен быть единственной линией обороны. Он может ловить грубые шаблоны, но блокировка слов “ignore”, “jailbreak” или “override” способна задеть документацию, вопросы о безопасности и обычный текст. Результат фильтра не равен доказательству злого умысла. Вместо безусловной блокировки для каждого совпадения настройте осмысленную политику: пропустить, направить на дополнительную проверку, попросить уточнить или отклонить конкретное действие. Записывайте причину решения и регулярно проверяйте долю ложных блокировок. Один regex, которому вы доверили безопасность, обычно просто создаёт красивую дыру в отчёте.
Выход модели также остаётся недоверенным, даже если вход прошёл модерацию. Экранируйте вывод при показе в браузере, проверяйте типы и допустимые значения структурированных полей, а перед вызовом инструмента повторно выполняйте авторизацию в доверенном коде. Не исполняйте сгенерированные команды автоматически. Если бизнес-процесс требует отправить письмо, изменить запись или удалить файл, показывайте человеку конкретное действие и получателей до подтверждения. Это важнее запрета слов: даже нераспознанная инъекция не должна обходить полномочия и подтверждение.
- Применяйте фильтр как дополнительный сигнал
- Валидируйте схему ответа и экранируйте вывод
- Проверяйте каждое действие в серверном коде
Изоляция и минимальные полномочия
Давайте приложению и подключённым инструментам ровно те полномочия, которые нужны конкретной задаче. Поиск справки не требует права отправлять письма; суммаризация документа не требует доступа ко всему файловому хранилищу. Разделяйте операции чтения и изменения, ограничивайте область поиска пользователем и проверяйте разрешения на каждом запросе. OWASP рекомендует принцип наименьших привилегий и отдельный контроль доступа к backend-функциям. Если модель предложила вызвать инструмент, сервер проверяет, допустим ли вызов для этого пользователя и этого процесса. Модель не является системой авторизации, даже если ей подробно описать роли.
Отдельный контейнер или процесс может сузить последствия компрометации прокси, если права ОС, файловая система и сетевые соединения действительно ограничены. Само слово «контейнер» ничего не изолирует от автоматически: задайте непривилегированного пользователя, выдавайте только необходимые файлы, ограничьте доступ к секретам и исходящие соединения по реальным потребностям. Не наделяйте сервис правом запускать команды, если его задача — только формировать запрос к API. Но не пишите, будто контейнер «клетка для вируса» или полная гарантия. Ошибка в настройках, права хоста и доступный ему токен остаются частью общей модели угроз.
Совет привязать API-токен к IP и обещать, что украденный ключ нельзя будет использовать из другой сети, слишком категоричен. Такая возможность зависит от конкретного поставщика и сетевой схемы, а IP-ограничение не делает секрет неуязвимым. Храните ключи в подходящем менеджере секретов или защищённой конфигурации, не включайте их в клиентский код, логи и промпты, ограничивайте права ключа и меняйте его при подозрении на утечку. Срок действия и ротацию выбирайте по возможностям сервиса и операционным требованиям; универсального короткого срока для всех API нет. Ключ, который доступен браузеру, уже не секрет — это факт, не метафора.
Не передавайте модели общий токен с правами всего приложения. Если сервис вызывает внутренние API, посредник должен действовать от имени конкретного пользователя или проверять его разрешения собственными правилами. Ограничьте доступ к отдельным ресурсам, операциям и наборам данных; разделите полномочия для чтения и записи. При высоком риске требуйте подтверждения пользователя перед необратимыми или внешне видимыми действиями. Эти меры снижают возможный ущерб, даже когда детектор не распознал инъекцию. OWASP прямо рекомендует, чтобы критические контроли доступа не делегировались самой модели.
Шифрование, резервные копии и сетевые зоны полезны для защиты системы в целом, но они не решают задачу prompt injection автоматически. Не дублируйте их в этой статье как магические средства против атак на контекст. Связывайте меру с угрозой: шифрование помогает защищать данные при хранении и передаче при корректном управлении ключами; резервная копия помогает восстановиться после потери; сегментация ограничивает сетевые пути. А чтобы бот не показал чужой документ, проверяйте права до выдачи документа. Разные меры нужны для разных отказов — иначе список контроля превращается в интерьерный каталог технологий.
- Разделяйте чтение, изменение и отправку данных
- Выдавайте минимум прав сервису и API-ключам
- Требуйте подтверждение перед значимым действием
Журналы, тестирование и план реакции
Журналируйте достаточно, чтобы восстановить последовательность событий: кто обратился, какой инструмент вызывался, какое решение принял сервер и прошла ли проверка полномочий. Не записывайте бездумно полные промпты, токены, персональные данные и секреты: сами логи могут стать источником утечки. Маскируйте чувствительные поля, ограничивайте круг доступа и срок хранения. Метрика «отклонённые запросы» полезна только вместе с контекстом: один всплеск может означать автоматизированную атаку, некорректный клиент или чрезмерно строгий фильтр. Сигнал должен вести к разбору, а не к автоматическому наказанию пользователя.
Блокировать IP при каждом всплеске — не универсальный рецепт. Пользователи могут выходить через общие адреса, а атакующий — менять адрес; блокировка иногда отрежет легитимную работу и не затронет косвенные инструкции в документах. Выбирайте меры по наблюдаемому поведению и устройству сервиса: ограничение частоты для подтверждённого злоупотребления, приостановка конкретного инструмента, отзыв скомпрометированного ключа или временная ручная проверка. Сначала выясните, что именно сработало и какие данные могли быть затронуты. Не делайте вывод «атака заблокирована» только по записи, что запрос отклонён: нужно убедиться, что действие не выполнилось другим путём.
Проверяйте систему на прямые запросы, инструкции во вложенных файлах, выдачу лишних документов, ответы с недопустимыми полями и попытки вызвать неразрешённый инструмент. Проверка должна включать не только фильтр, но и фактическую реакцию авторизации, журналирования и подтверждения. Проводите её на тестовых данных и отдельно фиксируйте ожидаемый результат: отказ, безопасная выдача, требование подтверждения или пропуск. При изменении промпта, набора документов, инструмента или модели повторяйте важные сценарии. Это инженерный контроль изменений, а не обещание однажды «проверить все атаки».
Для условной компании «Циркон-Строй» я бы начал с инвентаризации подключённых источников и прав бота, а не с покупки «волшебного фильтра». Сначала исключил бы ненужные действия и проверил, что пользователь не может запросить документы за пределами своих полномочий. Затем добавил бы проверку каждого вызова инструмента, безопасную обработку ответа и журналы с маскированием секретов. Уже после этого можно сравнить фильтры и классификаторы на собственном наборе прямых и косвенных атак. Так мы поймём, какой именно слой помогает и сколько обычных запросов он ошибочно задерживает. Это рекомендуемый план, не описание уже выполненной работы у клиента.
План реагирования должен отвечать на простые вопросы: кто отключает инструмент, кто отзывает ключ, кто проверяет доступ к данным, где фиксируется решение и как восстанавливается штатная работа. При подозрении на инцидент ограничьте потенциально опасные функции, проверьте журналы и область доступа, смените затронутые секреты и сообщите ответственным по внутреннему процессу. Не храните «системный промпт» как единственную копию бизнес-правил или секретов. Документируйте факты, а не догадки: время, источник контента, вызванный инструмент, затронутые записи и подтверждённые действия. Обнаруженная попытка, сработавший фильтр и подтверждённая утечка — три разные записи в отчёте.
Защита не сводится к непрерывному обновлению запрещённых фраз. Пересматривайте модель угроз, права и источники данных, когда меняется функциональность; тестируйте изменения и анализируйте ошибки фильтра. OWASP советует adversarial testing и симуляции атак, но это не означает, что нужен фиксированный еженедельный график или что мониторинг сам предотвращает инъекции. Частоту определяют скорость изменений и цена ошибки. Важна обратная связь: результаты проверки должны приводить к поправкам в авторизации, логике инструментов или обработке данных. Если единственный итог аудита — новый список слов, аудит не дошёл до причины.
- Фиксируйте вызовы инструментов, решения и результат проверки
- Маскируйте секреты и персональные данные в журналах
- Проверяйте цепочку на тестовых данных после изменений
Частые вопросы
Можно ли полностью исключить промпт-инъекцию?
Нет подтверждённого универсального способа гарантированно исключить этот класс риска. Ограничивайте доступные данные и действия, проверяйте ответы и требуйте подтверждение для значимых операций.
Помогает ли хранение системного промпта в отдельном файле?
Это упрощает управление инструкциями, но не мешает модели реагировать на недоверенный текст в контексте. Секреты и права доступа нужно защищать средствами приложения.
Достаточно ли фильтра запрещённых слов?
Нет. Он может ловить известные шаблоны, но пропускает другие формулировки и иногда блокирует обычные запросы. Используйте его только как дополнительную проверку.
Что делает Prompt Guard 2?
Это классификатор Meta для обнаружения известных prompt-атак и jailbreak. Его нужно оценивать на собственных данных; он не заменяет контроль прав, проверку действий и обработку результата.
Нужно ли блокировать IP при срабатывании фильтра?
Не автоматически. Сначала проверьте характер события и возможный ущерб. IP-блокировка может задеть общих пользователей и не закрывает атаки через документы или другие источники.
Источники
- OWASP LLM01:2025 Prompt Injection — Риски prompt injection и меры снижения воздействия: https://genai.owasp.org/llmrisk/llm01-prompt-injection/
- OWASP LLM02: Insecure Output Handling — Проверка и безопасная обработка вывода модели: https://genai.owasp.org/llmrisk2023-24/llm02-insecure-output-handling/
- Meta Llama Prompt Guard 2 Model Card — Назначение, модели и ограничения классификатора: https://github.com/meta-llama/PurpleLlama/blob/main/Llama-Prompt-Guard-2/86M/MODEL_CARD.md
- NIST AI 600-1 — Профиль рисков генеративных систем, включая информационную безопасность: https://doi.org/10.6028/NIST.AI.600-1
- RFC 9110: HTTP Semantics — Определения HTTP-кодов 400 и 422: https://www.rfc-editor.org/rfc/rfc9110.html



