{ "index": 145, "slug": "editorial-2023-12-field-security-audit", "title": "Аудит веб-проекта: как превратить список рисков в безопасный порядок исправлений", "excerpt": "Высокий score не говорит, что менять первым. Разбираем security-triage через evidence, границы системы, владельца, обратимый шаг и проверяемый критерий результата.", "contentHtml": "
После аудита команда часто получает длинный список пунктов. В одном есть версия зависимости. В другом — вопрос к авторизации. В третьем неясно, кто выдаёт загруженный файл. Заголовки звучат одинаково тревожно, но доказательства различаются. Если первым исправить самый громкий пункт, можно потратить релиз на косметическую правку и оставить публичный путь без владельца. Поспешное изменение может сломать рабочий сценарий. Цена ошибки — простой пользователей, потеря данных или новый обход защиты.
\nБезопасный triage начинается не со score. Он отвечает на четыре вопроса: что наблюдается, какая граница затронута, кто подтверждает контракт и какой следующий шаг можно отменить. Severity помогает описывать риск. Она не назначает владельца, не даёт разрешение на проверку и не доказывает наличие уязвимости.
\nРазделите карточку риска на пять частей: evidence, exposure, owner, reversibility и decision. Evidence связывает утверждение с источником. Exposure показывает путь от внешнего входа к данным или действию. Owner подтверждает границу и принимает изменение. Reversibility описывает возврат. Decision объясняет, почему пункт идёт сейчас.
\nЗапись «проверить границу авторизации API» — вопрос. Запись «любой пользователь читает чужой заказ» — утверждение, которому нужны воспроизводимый сценарий, разрешённая среда и зафиксированный результат. Пока этих условий нет, карточка имеет статус evidence gap. Нельзя поднимать её до подтверждённой уязвимости только потому, что она выглядит правдоподобно.
\nCVSS описывает характеристики уязвимости и помогает сравнивать техническую тяжесть. Но score не видит карту продукта. Он не знает, какой путь критичен для бизнеса, согласован ли тест, принадлежит ли endpoint вашей команде и что произойдёт после изменения. Поэтому высокий Base score может ждать уточнения, а менее громкий пункт с неизвестной публичной границей — получить первый безопасный gate.
\nПорядок должен быть объясним одним предложением: «Сначала подтверждаем владельца и ожидаемый отказ на публичной границе доступа, затем согласуем контракт identity-провайдера, после этого меняем выдачу файла с готовым rollback». Если такую фразу нельзя составить, список смешивает проверку фактов, согласование scope и разработку.
\n| Симптом | Причина | Проверка | Действие |
|---|---|---|---|
| Самый высокий score всегда первый | Severity подменяет контекст | Запросить claim, источник и ограничение | Обосновать порядок evidence и exposure |
| Есть домен, но нет границы | Актив и third-party путь смешаны | Нарисовать один пользовательский маршрут | Убрать неподтверждённый участок |
| «Добавим проверку доступа» без теста | Решение опередило критерий | Назвать ожидаемый allow и deny | Написать validation до кода |
| Rollback означает «откатить» | Не названы версия и ответственный | Проверить обратное действие | Назначить owner и stop condition |
| security.txt считают разрешением | Disclosure смешали с authorization | Проверить объект, метод и время | Без согласования ограничиться инвентаризацией |
Карточка не обязана быть большой. Поле claim описывает факт или вопрос, а не решение. source указывает журнал, запрос, конфигурацию, владельца или документ. status различает hypothesis, observed и confirmed. В limit записывают то, чего проверка не показывает.
const card = {\n id: 'SEC-042',\n claim: 'роль reader получает чужой заказ',\n scope: 'orders-api / GET /orders/:id',\n owner: 'orders-team',\n status: 'hypothesis',\n source: 'reproduction-2026-08-02-01',\n expected: { allow: 'свой заказ', deny: 'чужой заказ: 403' },\n limit: 'тестовая среда; production не проверялся',\n next: 'согласовать сценарий с владельцем API',\n rollback: 'изменений в системе нет'\n};\n\nif (card.status === 'hypothesis') {\n console.log('Не называть карточку подтверждённой уязвимостью');\n}\nПример учебный. Он не отправляет запросы, не получает токены и не доказывает поведение API. Его задача — показать форму записи. В настоящем отчёте идентификатор источника должен вести к разрешённому материалу. Не вставляйте пароль, токен, персональные данные или полный ответ, если для вывода достаточно хеша, фрагмента и защищённой ссылки.
\nЕсли scope не подтверждён, активная проверка останавливается. Не стоит проверять путь на домене, который может принадлежать подрядчику. Если владелец неизвестен, назначьте вопрос и сохраните evidence gap. Если тест требует необратимой миграции, сначала проведите отдельный review изменения. Если после фикса нет безопасного способа проверить отказ, решение не готово.
\nТа же логика работает для upload delivery. Нельзя считать файл защищённым только потому, что форма требует входа. Нужно проверить границу выдачи, серверное имя, место хранения, содержимое и авторизацию на чтении. Нельзя считать файл уязвимым только из-за расширения в URL. Нужны наблюдаемый сценарий и согласованный метод.
\nМатрица triage не заменяет penetration test, threat model, code review или incident response. Она не вычисляет business impact и не обещает срок исправления. OWASP ASVS задаёт проверяемые требования, но не знает архитектуру проекта. CVSS помогает описать тяжесть, но не выбирает владельца и не создаёт разрешение. RFC 9116 описывает канал раскрытия, а не право тестировать домен.
\nИсточники могут обновляться. Поэтому в отчёте фиксируйте версию стандарта и идентификатор требования. Не пишите «проверено по OWASP» без названия документа, версии, scope и метода. Не выдавайте учебный объект, синтетическую запись или локальный тест за production evidence.
\nКарточка готова к исправлению, когда другой инженер без устного контекста может ответить на пять вопросов: какой факт или вопрос проверяется; какая граница входит в scope; кто разрешил и принимает решение; какой результат подтвердит или опровергнет гипотезу; как вернуть изменение и кто это сделает. У карточки есть источник, версия метода, ограничение и дата следующей проверки.
\nЕсли хотя бы одного ответа нет, готов не fix, а следующий gate. Это проверяемый результат аудита. Он снижает риск ошибочной правки и сохраняет отрицательный путь: команда знает, когда остановиться.
\n