中文翻译暂不可用,显示俄语原文。
Реализовать fuzzing для агента
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Реализовать fuzzing для агента
1. Цель задачи
Научиться проектировать и выполнять фаззинг-тестирование LLM-агента, генерируя граничные, пустые, чрезмерно длинные и структурно некорректные запросы. Цель — выявить нештатное поведение (краши, зависания, неадекватные ответы, утечки контекста) до попадания в production.
Ключевой результат Рабочий фаззер, который за 1 час прогона находит не менее 3 различных уязвимостей/ошибок в целевом агенте (либо доказывает их отсутствие при покрытии тестовых сценариев).
2. Исходные данные
Перед началом необходимо иметь:
| Что нужно | Откуда взять |
|---|---|
| Целевой агент (API или локальный класс) | Собственный пет-проект / тестовый агент из учебного курса |
| Документация агента (список команд, параметры) | README, OpenAPI spec, docstrings |
| Токен / ключ API (если внешний сервис) | Личный аккаунт разработчика (тестовый лимит) |
| Таймауты и квоты для тестовой среды | Настройки окружения (рекомендуется staging) |
Если нет реального агента — симулируем:
- Напишите простого агента на Python (например, на базе LangChain или простой цепочки if-else), который принимает текстовый запрос и возвращает ответ. Агент должен обрабатывать команды
calc,translate,weather(имитация). - Намеренно добавьте 2-3 уязвимости: превышение длины входной строки (буфер), некорректное распознавание пустого запроса (краш), рекурсивный вызов при определённом шаблоне.
- Запустите его как локальный Flask/FastAPI сервер на порту 8000.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Язык | Python 3.10+ | Реализация фаззера |
| Фреймворк тестирования | pytest, hypothesis | Генерация стратегий fuzzing |
| HTTP-клиент | requests, aiohttp | Отправка запросов к агенту |
| Генерация данных | Faker, custom strategies | Граничные, пустые, длинные строки |
| Мониторинг | time, logging | Фиксация таймингов и ошибок |
| Отчёт | json, markdown | Сохранение результатов |
| Агент (тестируемый) | Flask/FastAPI / LangChain | Целевая система |
4. Этапы выполнения
Этап 1: Подготовка окружения и тестируемого агента (30-45 минут)
Действия
- Установите зависимости:
pip install hypothesis pytest requests faker - Разверните тестового агента (если используете симуляцию):
- Создайте файл
agent_server.pyс простым агентом, обрабатывающим команды:from flask import Flask, request, jsonify app = Flask(__name__) def handle_calc(expr): try: return str(eval(expr)) # уязвимость: eval! except: return "Error" def handle_translate(text): if len(text) > 1000: raise ValueError("Too long") return "translated: " + text @app.route("/agent", methods=["POST"]) def agent(): data = request.json cmd = data.get("cmd", "") arg = data.get("arg", "") if cmd == "" or arg is None: return jsonify({"error": "empty"}), 400 if cmd == "calc": return jsonify({"result": handle_calc(arg)}) if cmd == "translate": return jsonify({"result": handle_translate(arg)}) # ... другие команды
- Создайте файл
- Запустите сервер: python agent_server.py
- Убедитесь, что агент отвечает на простые запросы (например,
{"cmd":"calc", "arg":"2+2"}).
Ожидаемый результат этапа Работающий локальный сервер агента, готовый к фаззингу.
Этап 2: Проектирование стратегий fuzzing (45-60 минут)
Действия
- Определите контракт агента (формат входа, возможные поля, типы).
- Поля:
cmd(строка),arg(строка), опционально params (объект). - Допустимые команды:
calc,translate,weather.
- Поля:
- Выделите граничные случаи для каждой команды:
- Пустые строки:
"",None. - Очень длинные строки: >10 000 символов.
- Строки с управляющими символами:
\x00,\n,\r,\t. - Невалидные JSON (если агент ожидает JSON, отправьте бинарные данные).
- Спецсимволы: SQL-инъекции, XSS-попытки.
- Команды, не существующие в агенте.
- Огромное количество вложенных объектов (если принимается JSON).
- Пустые строки:
- Запишите сценарии в виде Hypothesis strategies:
from hypothesis import given, strategies as st # Стратегия для поля cmd cmd_strategy = st.text( min_size=0, max_size=100, alphabet=st.characters(whitelist_categories=('L', 'N', 'P'), blacklist_characters='\x00') ) | st.none() | st.just('\x00' * 10) # Стратегия для поля arg arg_strategy = st.text(min_size=0, max_size=20000) # ...
Ожидаемый результат этапа Документированный набор стратегий (в коде или таблице) с указанием ожидаемого поведения.
Этап 3: Реализация фаззера (1-1.5 часа)
Действия
- Напишите основной скрипт
fuzzer.py- Используйте Hypothesis с декоратором
@givenдля генерации запросов. - Отправляйте POST-запросы к http://localhost:8000/agent.
- Ловите исключения (connection error, timeout, HTTP errors).
- Фиксируйте:
- Время ответа.
- Статус код.
- Наличие краша (если сервер упал).
- Размер ответа.
- Необычные строки в ответе (например, "Error", "Traceback").
- Используйте Hypothesis с декоратором
- Добавьте фильтрацию ложных срабатываний
- Пропускайте ожидаемые HTTP 400/500 (агент их допускает).
- Фиксируйте только неожиданные: 200 вместо 400, краш процесса, бесконечное выполнение.
- Реализуйте защиту от долгих запросов
- Установите таймаут 5 секунд.
- Если запрос не завершился — логируйте TIMEOUT.
- Пример структуры
import requests from hypothesis import given, settings, strategies as st import logging logging.basicConfig(filename='fuzz.log', level=logging.INFO) @settings(max_examples=200, deadline=5000) @given( cmd=st.text(min_size=0, max_size=200), arg=st.text(min_size=0, max_size=5000) ) def test_agent(cmd, arg): payload = {"cmd": cmd, "arg": arg} try: resp = requests.post("http://localhost:8000/agent", json=payload, timeout=3) # Анализ ответа if resp.status_code == 200 and resp.elapsed.total_seconds() > 2: logging.warning(f"Slow response: {cmd=} {arg=}") if resp.status_code == 500: logging.error(f"Server error: {cmd=} {arg=}") if not resp.headers.get('Content-Type'): logging.warning(f"No content-type: {cmd=} {arg=}") except requests.exceptions.ConnectionError: logging.critical(f"Agent crashed! {cmd=} {arg=}")
Ожидаемый результат этапа Рабочий скрипт fuzzer.py, который можно запустить и наблюдать логи.
Этап 4: Запуск фаззера и анализ результатов (30-60 минут)
Действия
- Запустите фаззер pytest fuzzer.py -v --hypothesis-show-statistics
- Наблюдайте за логами в реальном времени смотрите fuzz.log.
- При обнаружении краша агента
- Восстановите агента (перезапустите сервер).
- Запишите конкретный входной запрос, вызвавший краш.
- Классифицируйте проблему (null pointer, переполнение буфера, бесконечная рекурсия).
- Соберите статистику
- Количество выполненных тестов.
- Количество ошибок (категории: CRASH, TIMEOUT, UNEXPECTED_200, etc.).
- Минимальное воспроизводящее значение (shrunk example).
- Повторите с увеличенным числом примеров (
--max-examples=1000) для лучшего покрытия.
Ожидаемый результат этапа Список найденных уязвимостей (минимум 3) с воспроизводимыми примерами.
Этап 5: Оформление отчёта (30 минут)
Действия
- Создайте файл
fuzzing_report.mdсо следующей структурой:- Цель и методы (кратко).
- Конфигурация фаззера (гипотезы, количество примеров).
- Результаты по категориям
- Краши агента (с примерами запросов).
- Неожиданные таймауты.
- Ответы с некорректным HTTP-статусом.
- Другие аномалии.
- Критичность каждой уязвимости (P0-P3).
- Воспроизводимые примеры (JSON-запросы).
- Рекомендации по исправлению.
- Приложите лог-файл (
fuzz.log) как доказательство.
Ожидаемый результат этапа Готовый отчёт с тремя и более задокументированными уязвимостями или заключением об отсутствии таковых при заданном покрытии.
5. Критерии приемки (Definition of Done)
- Фаззер написан на Python с использованием Hypothesis.
- Фаззер способен генерировать граничные, пустые, длинные запросы (не менее 5 различных стратегий).
- Фаззер корректно обрабатывает сетевые ошибки и таймауты.
- За 200-500 примеров найдено хотя бы 3 нештатных поведения (краш, зависание, неожиданный 200).
- Каждый найденный дефект воспроизводится отдельно (простой тестовый скрипт).
- Написан отчёт в формате markdown с примерами запросов и рекомендациями.
- Результаты воспроизводимы на staging-окружении (или локальном).
- Код фаззера покрыт юнит-тестами (хотя бы базовая проверка стратегий).
6. Ожидаемый результат
- Основной артефакт файл
fuzzer.py— скрипт на Python с реализацией фаззинг-тестов. - Второстепенные
fuzzing_report.md— отчёт с описанием найденных уязвимостей.fuzz.log— лог выполнения.- (Опционально) Дополнение к CI-пайплайну для автоматического запуска фаззера при каждом релизе агента.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Агент долго отвечает на большие запросы | Установить таймаут 3-5 секунд; логировать таймауты как отдельную категорию. |
| Rate limiting (агент возвращает 429) | Настроить hypothesis max_examples и добавить небольшую задержку между запросами (time.sleep(0.1)). |
| Ложные срабатывания (ожидаемые ошибки) | Фильтровать ожидаемые коды (400, 404) и логировать только неожиданные (200 вместо 400, краш). |
| Сложность воспроизведения (хитрая комбинация) | Использовать встроенный в Hypothesis механизм shrink: после нахождения ошибки он автоматически уменьшит входные данные до минимального набора. |
| Остановка фаззера из-за критической ошибки | Запускать фаззер в режиме --hypothesis-verbosity=debug и обернуть каждый тестовый случай в try-except, с восстановлением агента (скрипт рестарта). |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| 1. Подготовка окружения и тестируемого агента | 30-45 мин |
| 2. Проектирование стратегий fuzzing | 45-60 мин |
| 3. Реализация фаззера | 1-1.5 часа |
| 4. Запуск фаззера и анализ результатов | 30-60 мин |
| 5. Оформление отчёта | 30 мин |
| Итого | ~3.5 - 5 часов |
Примечание При первом выполнении задачи возможен запас в 30-60 минут на изучение Hypothesis и отладку.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 12 | Что такое fuzzing и зачем он нужен в тестировании агентов? |
| 45 | Как генерировать краевые случаи с помощью Hypothesis? |
| 78 | Разница между фаззингом на основе мутаций и генерации. |
| 112 | Как обрабатывать таймауты в асинхронных тестах? |
| 156 | Интеграция фаззинга в CI/CD пайплайн. |
| 203 | Примеры уязвимостей LLM-агентов (injection, buffer overflow). |
| 287 | Метрики покрытия для фаззинг-тестов. |
| 315 | Как симулировать атаки на агента (prompt injection) через фаззинг? |
| 402 | Использование Atheris для фаззинга Python-библиотек. |
| 567 | Анализ логов фаззинга и классификация ошибок. |
10. Чек-лист самопроверки
- Я установил Hypothesis, pytest, requests и Faker.
- У меня есть рабочий тестовый агент (собственный или симулированный с известными уязвимостями).
- Я определил минимум 5 различных стратегий генерации запросов (пустые, длинные, невалидные JSON, спецсимволы, несуществующие команды).
- Я написал и запустил фаззер, который за 500 примеров нашёл хотя бы 3 аномалии.
- Я воспроизвёл каждую найденную проблему отдельным простым тестом (curl или Python-запрос).
- Я написал отчёт в формате markdown и приложил лог.
- Я убедился, что фаззер не генерирует слишком много ложных срабатываний (отфильтровал ожидаемые коды).
- Я проверил, что фаззер корректно логирует таймауты и краши сервера.
- Я сохранил все файлы (fuzzer.py, report, log) в репозиторий проекта.