8 lines
15 KiB
JSON
8 lines
15 KiB
JSON
{
|
||
"index": 179,
|
||
"slug": "editorial-2023-01-mechanism-threat-model",
|
||
"title": "Модель угроз без догадок: связать актив, риск и проверяемый контроль",
|
||
"excerpt": "Как превратить разговор о безопасности в проверяемую связь: назвать актив, границу и злоупотребление, выбрать контроль и заранее определить evidence для отрицательного пути.",
|
||
"contentHtml": "<p>В ревью появляется знакомый симптом: в изменении уже назван контроль — подпись, шифрование, rate limit или дополнительная проверка, — но никто не может ответить, какой актив он защищает и какой вход должен быть отвергнут. Обсуждение быстро сводится к вкусу: один инженер предлагает JWT, другой — mTLS, третий — ещё один middleware. Цена ошибки — ложное закрытие риска. Команда может потратить время на защиту не той границы, а при откате не сможет объяснить, какую гарантию она снимает.</p>\n<p>Тезис статьи простой: модель угроз полезна только тогда, когда связывает четыре наблюдаемых вещи — актив, злоупотребление, контроль и evidence. Название технологии не заменяет эту связь. Сначала нужно зафиксировать, что важно сохранить, какое действие нарушает это свойство, где система принимает решение и чем команда увидит отказ. Такой минимальный контракт не доказывает безопасность продукта. Он делает решение проверяемым и показывает, чего ещё не хватает.</p>\n<h2>Механизм: от актива к доказательству</h2>\n<p>Возьмём учебный поток: browser-client отправляет change-request через границу public-api-to-handler, обработчик принимает или отклоняет запрос, затем записывает его в store. Актив — не «данные вообще», а конкретный change-request. Злоупотребление — отправить запрос без valid signature. Контроль — проверять подпись до записи. Evidence — наблюдаемый отказ на неподписанном входе.</p>\n<p>У каждого поля есть один вопрос. Asset отвечает: «что потеряет свойство при ошибке?». Abuse отвечает: «какое действие мы пытаемся остановить?». Boundary отвечает: «где вход перестаёт быть доверенным?». Control отвечает: «какое решение примет система?». Evidence отвечает: «что увидит проверяющий и по какому признаку скажет pass или fail?». Если поле заменяют словами «система», «безопасность» или «проверено», модель теряет смысл.</p>\n<table><caption>Минимальная связь в одном потоке</caption><thead><tr><th>Элемент</th><th>Учебное значение</th><th>Проверяемый вопрос</th><th>Что не следует из записи</th></tr></thead><tbody><tr><td>Actor</td><td>browser-client</td><td>кто формирует вход?</td><td>личность пользователя и его права</td></tr><tr><td>Asset</td><td>change-request</td><td>что нужно сохранить?</td><td>классификация всех данных продукта</td></tr><tr><td>Boundary</td><td>public-api-to-handler</td><td>где меняется доверие к входу?</td><td>полная топология сети</td></tr><tr><td>Abuse</td><td>unsigned request</td><td>какое действие не должно пройти?</td><td>полный список атак</td></tr><tr><td>Control</td><td>signed-request</td><td>какое условие проверяет handler?</td><td>достаточность криптографии</td></tr><tr><td>Evidence</td><td>local rejection check</td><td>какой отказ можно наблюдать?</td><td>результат production-проверки или pentest</td></tr></tbody></table>\n<h2>Конкретный пример: строгий контракт для отрицательного пути</h2>\n<p>Ниже — учебный JavaScript-пример. Он не создаёт ключи, не подписывает HTTP-запросы и не обращается к базе. Функция проверяет только полноту описания потока. Это полезно для иллюстрации механизма: пропущенный актив или неизвестный контроль не превращаются в молчаливую догадку.</p>\n<pre><code>function planThreatModel(input) {\n const required = ['actor', 'asset', 'boundary', 'abuse', 'control', 'evidence'];\n const missing = required.filter((key) => !input[key]);\n\n if (missing.length > 0) {\n return { status: 'reject', reason: `missing: ${missing.join(', ')}` };\n }\n\n const allowedControls = ['signed-request', 'explicit-authorization'];\n if (!allowedControls.includes(input.control)) {\n return { status: 'reject', reason: 'unknown-control' };\n }\n\n return {\n status: 'accept',\n contract: {\n asset: input.asset,\n abuse: input.abuse,\n control: input.control,\n evidence: input.evidence\n }\n };\n}\n\n// Учебный вызов: это не проверка реального endpoint.\nplanThreatModel({\n actor: 'browser-client',\n asset: 'change-request',\n boundary: 'public-api-to-handler',\n abuse: 'unsigned request',\n control: 'signed-request',\n evidence: 'local rejection check'\n});</code></pre>\n<p>Положительный результат здесь означает только то, что запись содержит нужные поля и знакомый контроль. Он не означает, что подпись реализована правильно, ключи защищены, права проверены или запрос нельзя подделать другим способом. Отрицательный путь важнее happy path: пустой asset, отсутствующая boundary и неизвестный control должны остановить описание. В рабочем коде такой контракт нужно дополнить тестом самого handler, а затем отдельно проверить интеграцию и эксплуатационные границы.</p>\n<figure><img src=\"/assets/editorial/2023/threat-model-2023-contract.svg\" alt=\"Учебная схема связи актива, злоупотребления, контроля и evidence в модели угроз\"><figcaption>Учебная схема показывает связь change-request, unsigned request, signed-request и local rejection check. Она не описывает реальную сеть, ключи или результаты проверки.</figcaption></figure>\n<h2>Симптом → причина → проверка → действие</h2>\n<table><caption>Диагностика неполной модели</caption><thead><tr><th>Симптом</th><th>Причина</th><th>Проверка</th><th>Действие</th></tr></thead><tbody><tr><td>Есть control, но нет asset</td><td>выбрали привычную технологию</td><td>какой объект теряет свойство?</td><td>назвать один asset до выбора механизма</td></tr><tr><td>Есть threat, но нет boundary</td><td>не указано место решения</td><td>где вход меняет статус доверия?</td><td>показать одну границу на потоке</td></tr><tr><td>Есть control, но нет evidence</td><td>не описан отрицательный путь</td><td>какой вход должен получить отказ?</td><td>добавить test, log или ручную проверку</td></tr><tr><td>В evidence написано «проверено»</td><td>не назван метод и результат</td><td>что именно увидит другой инженер?</td><td>указать вход, ожидаемый отказ и артефакт</td></tr><tr><td>Rollback означает «вернуть всё»</td><td>модель смешана с выпуском</td><td>какие поля и ресурсы реально меняются?</td><td>разделить snapshot договора и план отката</td></tr></tbody></table>\n<h2>Порядок действий</h2>\n<ol><li><strong>Сузьте область.</strong> Возьмите один поток, один актив и одну границу. Не пытайтесь описать весь продукт одной диаграммой.</li><li><strong>Назовите злоупотребление глаголом.</strong> Формулировка «отправить запрос без действительной подписи» проверяемее, чем слово «подделка».</li><li><strong>Определите решение.</strong> Запишите, в какой точке handler должен принять или отклонить вход. Не выдавайте имя технологии за условие.</li><li><strong>Опишите evidence.</strong> Укажите конкретный вход, ожидаемый результат и артефакт: unit test, журнал решения или согласованную ручную проверку.</li><li><strong>Проверьте отрицательную ветку.</strong> Передайте пустой asset, неверный вход или неизвестный control. Система должна отказать явно, а не достроить контекст.</li><li><strong>Отделите модель от реализации.</strong> Сверьте контракт с реальным кодом, конфигурацией и владельцем ключей. Учебный пример не заменяет эти проверки.</li><li><strong>Запишите откат.</strong> Назовите, что возвращается при удалении контроля. Если меняются ключи, миграции, очереди или совместимость, нужен отдельный операционный план.</li></ol>\n<h2>Ограничения и отрицательный путь</h2>\n<p>Малая модель не ранжирует риск, не считает вероятность, не строит attack tree и не перечисляет все trust zones. Она не проверяет криптографический протокол, identity provider, права доступа, хранение секретов или журналирование. Если актив связан с персональными данными, платежами или критичной операцией, потребуется более подробная классификация, согласованный владелец риска и независимая проверка.</p>\n<p>Контроль может оказаться неверным даже при полной записи. Подпись не заменяет авторизацию. Шифрование канала не доказывает целостность бизнес-операции. Rate limit не решает проблему подмены личности. Нельзя переносить учебное signed-request на реальный API без проверки протокола, ключей, времени жизни, повторной отправки и обработки ошибок. Отрицательный результат модели — повод остановиться и уточнить решение, а не повод подобрать другое модное слово.</p>\n<h2>Проверяемый критерий готовности</h2>\n<p>Модель готова к следующему этапу, если независимый инженер без устных пояснений может назвать asset, злоупотребление, boundary, контроль и evidence; воспроизвести отрицательную проверку; увидеть однозначный pass или fail; и понять, что именно откатывается. Это критерий полноты записи, а не сертификат безопасности. Для реализации нужен отдельный критерий: тест должен пройти на настоящем handler с разрешённым входом и явно заданным неподписанным входом, а результат должен принадлежать согласованному артефакту проверки.</p>\n<h2>Проверяемые источники</h2>\n<ul><li><a href=\"https://cheatsheetseries.owasp.org/cheatsheets/Threat_Modeling_Cheat_Sheet.html\" target=\"_blank\" rel=\"noopener noreferrer\">OWASP Threat Modeling Cheat Sheet</a> — практическая рамка: модель системы, поиск угроз, меры и проверка.</li><li><a href=\"https://csrc.nist.gov/pubs/sp/800/154/ipd\" target=\"_blank\" rel=\"noopener noreferrer\">NIST SP 800-154, Guide to Data-Centric System Threat Modeling</a> — Initial Public Draft; NIST указывает, что документ планируют финализировать, поэтому его нельзя цитировать как завершённый стандарт.</li><li><a href=\"https://csrc.nist.gov/pubs/sp/800/218/final\" target=\"_blank\" rel=\"noopener noreferrer\">NIST SP 800-218, Secure Software Development Framework v1.1</a> — официальная рамка практик безопасной разработки, а не доказательство корректности конкретного контроля.</li></ul>"
|
||
}
|