8 lines
18 KiB
JSON
8 lines
18 KiB
JSON
{
|
||
"index": 179,
|
||
"slug": "editorial-2023-01-mechanism-threat-model",
|
||
"title": "Модель угроз: от актива к проверяемому контролю",
|
||
"excerpt": "Как связать актив, злоупотребление, границу и контроль в одну проверяемую модель — с учебным контрактом, отрицательным путём и явными ограничениями.",
|
||
"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, а не «данные вообще». Злоупотребление — отправить запрос без действительной подписи. Граница — место, где вход перестаёт быть доверенным. Контроль — решение handler до записи. Evidence — наблюдаемый отказ на неподписанном входе.</p>\n<p>Эта схема содержит шесть полей, но отвечает на четыре вопроса. Что мы строим — actor, asset и boundary. Что может пойти не так — abuse. Что предпримем — control. Как поймём, что решение достаточно проверено, — evidence. Так модель не смешивает объект защиты, сценарий атаки и способ проверки.</p>\n<table><caption>Шесть полей одного потока</caption><thead><tr><th scope=\"col\">Поле</th><th scope=\"col\">Учебное значение</th><th scope=\"col\">Вопрос</th><th scope=\"col\">Граница вывода</th></tr></thead><tbody><tr><th scope=\"row\">Actor</th><td>browser-client</td><td>кто формирует вход?</td><td>не доказывает личность и права пользователя</td></tr><tr><th scope=\"row\">Asset</th><td>change-request</td><td>что нужно сохранить?</td><td>не заменяет классификацию всех данных</td></tr><tr><th scope=\"row\">Boundary</th><td>public-api-to-handler</td><td>где меняется доверие к входу?</td><td>не описывает полную топологию сети</td></tr><tr><th scope=\"row\">Abuse</th><td>unsigned request</td><td>какое действие не должно пройти?</td><td>не является полным списком атак</td></tr><tr><th scope=\"row\">Control</th><td>signed-request</td><td>какое условие проверяет handler?</td><td>не доказывает достаточность криптографии</td></tr><tr><th scope=\"row\">Evidence</th><td>local rejection check</td><td>что можно наблюдать?</td><td>не является результатом production-проверки или pentest</td></tr></tbody></table>\n<h2>Что в модели называют риском</h2>\n<p>Риск здесь — не название уязвимости и не оценка «высокий». Это связка сценария злоупотребления с последствием для актива. Если неподписанный change-request меняет запись, последствием становится потеря целостности этого актива. Контроль должен уменьшать именно такой путь, а evidence — показать, что неподписанный вход действительно не дошёл до записи.</p>\n<p>Количественную оценку риска эта заметка не вводит. Для неё потребовались бы вероятность, ущерб, стоимость исправления и согласованный способ приоритизации. Поэтому не стоит превращать слово «risk» в число без метода расчёта. Сначала зафиксируйте путь атаки и свойство актива, затем решайте, нужна ли отдельная оценка.</p>\n<h2>Воспроизводимый учебный пример</h2>\n<p>Ниже — небольшой JavaScript-валидатор записи модели. Он не создаёт ключи, не проверяет подпись HTTP-запроса и не обращается к базе. Его задача уже: не дать пропустить неполное описание потока или контроль, которого нет в согласованном наборе. Запускать пример можно в Node.js или в консоли браузера.</p>\n<pre><code>function checkThreatRecord(input = {}) {\n const required = ['actor', 'asset', 'boundary', 'abuse', 'control', 'evidence'];\n const missing = required.filter((key) => {\n return typeof input[key] !== 'string' || input[key].trim() === '';\n });\n\n if (missing.length > 0) {\n return { status: 'reject', reason: 'missing: ' + missing.join(', ') };\n }\n\n if (input.control !== 'signed-request') {\n return { status: 'reject', reason: 'control-not-approved' };\n }\n\n return {\n status: 'accept',\n asset: input.asset,\n abuse: input.abuse,\n control: input.control,\n evidence: input.evidence\n };\n}\n\nconst complete = {\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};\n\nconsole.log(checkThreatRecord(complete).status); // accept\nconsole.log(checkThreatRecord({ ...complete, asset: '' }).reason); // missing: asset\nconsole.log(checkThreatRecord({ ...complete, control: 'rate-limit' }).reason); // control-not-approved</code></pre>\n<p>Вызов с полной записью возвращает <code>accept</code>. Пустой asset и неподтверждённый control дают разные причины отказа. Это воспроизводимый результат именно для контракта описания. Он не означает, что реальный handler проверяет подпись, что ключи защищены, что запрос нельзя повторить или что пользователь имеет право изменить запись. Следующий тест должен обращаться к настоящему handler и проверять разрешённый и неподписанный входы отдельно.</p>\n<figure><img src=\"/assets/editorial/2023/threat-model-2023-contract.svg\" alt=\"Схема связи участника, актива, злоупотребления, контроля и доказательства в модели угроз\"><figcaption>Учебная схема связывает change-request, unsigned request, signed-request и local rejection check; она не описывает реальную сеть, ключи или результат проверки endpoint.</figcaption></figure>\n<h2>Где проверка меняет решение</h2>\n<p>Полезный поворот расследования происходит не при выборе нового middleware, а при проверке отрицательного пути. Если запись показывает контроль, но не показывает вход, который он должен отвергнуть, команда ещё не связала защиту с угрозой. Если evidence ограничено словом «проверено», другой инженер не сможет повторить вывод.</p>\n<table><caption>Симптом, проверка и действие</caption><thead><tr><th scope=\"col\">Симптом</th><th scope=\"col\">Проверка</th><th scope=\"col\">Действие</th><th scope=\"col\">Что ещё не доказано</th></tr></thead><tbody><tr><td>Есть control, но нет asset</td><td>какой объект теряет свойство?</td><td>назвать один asset до выбора механизма</td><td>что контроль защищает весь продукт</td></tr><tr><td>Есть abuse, но нет boundary</td><td>где вход меняет статус доверия?</td><td>показать границу на потоке</td><td>что другие входы устроены так же</td></tr><tr><td>Есть control, но нет evidence</td><td>какой вход должен получить отказ?</td><td>добавить тест, лог решения или ручную проверку</td><td>что реализация уже исправлена</td></tr><tr><td>Evidence равно «проверено»</td><td>какой вход, результат и артефакт?</td><td>записать три этих значения</td><td>что тест покрывает все ветви</td></tr><tr><td>Rollback равно «вернуть всё»</td><td>какие поля и ресурсы изменились?</td><td>описать границу отката отдельно</td><td>что удаление контроля безопасно</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> Проверьте настоящий handler, конфигурацию, владельца ключей, права и журналирование. Учебный валидатор эти свойства не проверяет.</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>OWASP описывает threat modeling как структурированный и повторяемый процесс: сначала моделируют систему, затем выявляют угрозы, выбирают меры и проводят review/validation. В этой рамке отдельно названы потоки данных, хранилища и trust boundaries, поэтому boundary в учебном контракте нельзя заменять общим словом «система».</p>\n<p>NIST SP 800-154 связывает data-centric threat modeling с четырьмя шагами: определить систему и интересующие данные, выбрать векторы атаки, охарактеризовать меры защиты и зафиксировать результаты. Это Initial Public Draft 2016 года, а страница NIST сообщает о планах финализации; документ нельзя цитировать как завершённый стандарт. Для конкретного проекта его ограничения и актуальность нужно проверять отдельно.</p>\n<h2>Проверяемый критерий готовности</h2>\n<p>Модель готова к следующему этапу, если независимый инженер без устных пояснений называет actor, asset, boundary, abuse, control и 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> — описание повторяемого процесса, моделирования системы, trust boundaries, мер и review/validation.</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>"
|
||
}
|