# module-05. Проектная спецификация `message-safety` > Статус: целевая production-спецификация MVP. > Канонические источники: [`README.md`](../architectory/README.md), [`arch-00-glossary.md`](../architectory/arch-00-glossary.md), [`arch-01-system-architecture.md`](../architectory/arch-01-system-architecture.md), [`arch-02-api-contracts.md`](../architectory/arch-02-api-contracts.md), [`arch-03-docker-compose-blueprint.md`](../architectory/arch-03-docker-compose-blueprint.md), [`arch-04-settings-and-content.md`](../architectory/arch-04-settings-and-content.md), [`arch-05-agent-development-process.md`](../architectory/arch-05-agent-development-process.md), [`module-01-api-backend.md`](module-01-api-backend.md). ## 1. Назначение и приоритет `message-safety` — внутренний сервис, который до отправки сообщения в Bitrix24 проверяет пользовательский текст, содержащиеся в нём ссылки и файлы из S3-quarantine. Сервис закрывает угрозы, поступающие через пользовательское сообщение: - управляющие и prompt-injection конструкции, направленные на оператора или последующую автоматическую обработку; - опасные URL-схемы, URL с credentials и ссылки на private/link-local/metadata адреса; - HTML/script-like payloads, способные стать активным содержимым при небезопасном отображении; - подмену типа файла, несоответствие заявленного MIME фактическому формату и checksum; - вредоносные файлы, обнаруживаемые антивирусными сигнатурами. Спецификация детализирует архитектуру, но не меняет её. При конфликте приоритет имеют `arch-00`…`arch-05`. Канонические domain outcomes: - `200 allow`; - `403 deny`; - `203 pending` с последующим sticky `200` или `403`. Test-only правила по первому символу, случайные verdict и terminal `400 stub_final_error` в production-контракт не входят. ## 2. Границы ответственности ### 2.1. Сервис отвечает за - строгую валидацию internal DTO; - нормализацию и rule-based проверку текста; - извлечение и проверку ссылок; - валидацию file metadata и фактического формата; - чтение файла из S3-quarantine по read-only credentials; - вычисление authoritative SHA-256; - антивирусную проверку файла через ClamAV; - выбор sync/async режима; - создание и исполнение async safety tasks; - sticky final verdict, verdict cache и audit в схеме `message_safety`; - task coordination/cache/rate limits в Redis DB2; - internal API, health, метрики, трассировку и безопасные JSON-логи. ### 2.2. Сервис не отвечает за - JWT пользователя, согласия и авторизацию доступа пользователя к диалогу; - edge/API rate limits; - загрузку файла и выдачу presigned URL; - запись пользовательского сообщения и статусов в `han_app`; - copy/promote файла из quarantine в S3-data и удаление объекта; - доставку в Bitrix24, realtime и пользовательский текст ошибки; - анализ входящих сообщений оператора; - ML-модерацию смысла, токсичности или правдивости текста. Этими операциями владеет `api-backend` или соответствующий архитектурный модуль. ## 3. Threat model MVP ### 3.1. Текст и ссылки | Угроза | Контроль | Результат | |---|---|---| | Prompt/control injection | Версионированные Unicode-aware rules | `403 deny` | | Попытка выдать текст за system/developer instruction | Нормализация + rule pack | `403 deny` | | Script/active-content payload | Правила для script, event-handler и опасных embedding-конструкций | `403 deny` | | Опасная URL-схема | Разрешены только `http` и `https` для распознанных web URL | `403 deny` | | URL с userinfo/credentials | Запрет `user:password@host` | `403 deny` | | SSRF-ссылка | DNS/IP classification, запрет private, loopback, link-local, multicast, unspecified и metadata endpoints | `403 deny` | | Обход Unicode/whitespace | NFKC, CRLF→LF, Unicode whitespace handling | Проверка нормализованного текста | | ReDoS/DoS правилами | Линейные/ограниченные regex, лимиты текста, URL и времени | `400` или dependency error | Rules не заменяют безопасный rendering. Frontend и Bitrix integration обязаны экранировать текст; safety является дополнительным барьером, а не HTML sanitizer. ### 3.2. Файлы | Угроза | Контроль | Результат | |---|---|---| | Недопустимый размер/MIME | Сверка DTO с allow-list и лимитами | `403 deny` | | Подмена MIME | Magic-byte/content sniffing, сверка declared MIME | `403 deny` | | Подмена содержимого после complete | Полный SHA-256 против DTO checksum | `403 deny` | | Malware | ClamAV scan актуальными сигнатурами | `403 deny` | | Архивная бомба/ресурсное истощение | Лимиты размера, stream scan, ClamAV limits/timeouts | deny при policy hit; error при сбое | | Polyglot/неоднозначный формат | Строгий формат detector и deny при mismatch/ambiguity | `403 deny` | | Повтор известного файла | Cache по SHA-256 + versions | Sticky cached verdict | MVP принимает только типы из `chat.attachments.allowed_extensions` и `chat.attachments.allowed_mime_types`, при `chat.attachments.max_size_mb`. Расширение проверяет `api-backend` до вызова safety; `message-safety` независимо проверяет MIME и фактический формат байтов. Internal DTO не содержит имени файла, поэтому сервис не выводит расширение из object key. ### 3.3. Вне threat model MVP - zero-day malware, отсутствующий в сигнатурах и эвристиках выбранного AV; - OCR изображений и semantic analysis PDF; - password-protected/encrypted containers: в MVP они запрещаются, если содержимое нельзя полностью проверить; - DLP/поиск персональных данных, токсичности и запрещённой тематики; - переход по пользовательской ссылке и анализ удалённой страницы. ## 4. Общий pipeline ```mermaid flowchart TD postCheck[POST_check] --> auth[Auth_and_DTO] auth --> kind{content_kind} kind -->|text| normalizeText[Normalize_text] normalizeText --> textRules[Text_rules] textRules --> linkRules[Link_pipeline] linkRules --> syncVerdict[200_or_403] kind -->|file| metadata[Metadata_validation] metadata --> cache{SHA256_cache} cache -->|hit| cached[Sticky_200_or_403] cache -->|miss| task[203_and_task] task --> worker[File_worker] worker --> objectRead[S3_stream_and_SHA256] objectRead --> formatCheck[Format_validation] formatCheck --> avScan[ClamAV_scan] avScan --> finalVerdict[Persist_sticky_verdict] finalVerdict --> taskGet[GET_task_200_or_403] ``` Приоритет: 1. service authentication, body/content-type/size и DTO validation; 2. idempotency/fingerprint conflict; 3. нормализация; 4. обязательные проверки для соответствующего `content_kind`; 5. любой deny имеет приоритет над allow; 6. инфраструктурная ошибка не превращается ни в allow, ни в domain deny. ## 5. Текстовый pipeline ### 5.1. Нормализация Pipeline детерминирован: 1. принять только JSON UTF-8; 2. заменить `CRLF`/`CR` на `LF`; 3. Unicode normalization `NFKC`; 4. удалить leading Unicode whitespace; 5. сохранить исходный регистр и punctuation для rules; 6. ограничить текст internal DTO до 10 000 Unicode code points; 7. вычислить SHA-256 нормализованного текста для correlation/cache без хранения текста. `content_kind=text` требует поле `text`; пустой текст отклоняется upstream `api-backend`. `content_kind=file` допускает пустой `text`; текстовые rules тогда не запускаются. ### 5.2. Rule engine Rules поставляются как статический read-only bundle приложения. Динамический код, regex или rule definitions из запроса запрещены. Каждое правило содержит: - стабильный `rule_id`; - `reason_code`; - severity; - scope (`text`, `url`, `file_metadata`); - action (`deny`); - `rules_version`; - тестовые positive/negative cases. Начальный rule pack MVP: - `text.prompt_instruction_override` — конструкции вида «игнорируй предыдущие инструкции» и эквиваленты на поддерживаемых языках; - `text.prompt_role_impersonation` — попытка обозначить пользовательский фрагмент как system/developer/tool instruction; - `text.prompt_secret_extraction` — запрос раскрыть system prompt, credentials, tokens или внутренние инструкции; - `text.active_script` — `