Перейти к содержанию

Модель угроз веб-приложения

Безопасность начинается с ответа на вопрос, какие действия приложение должно разрешать. Если у посетителя есть правильный пароль, это ещё не означает, что ему доступны чужие документы. Если строка выглядит как название статьи, она всё равно может стать программой в другом контексте. В этом курсе будем последовательно разбирать такие переходы.

Общий пример — security-lab, небольшая библиотека личных заметок. Учебные пользователи alice и boris владеют заметками 1 и 2. Данные вымышлены. После первого урока у нас появится модель угроз: что защищаем, кому доверяем и каким наблюдением подтвердим нужное поведение. Эта модель будет определять код следующих уроков.

Активы и действия

Активом называют то, потеря или изменение чего имеет значение для приложения. В нашей библиотеке это содержимое заметки, пароль пользователя, его сессия и доступность сервиса. Даже маленький проект имеет несколько разных активов. Защита только пароля не предотвращает чтение чужого текста, а ограничение доступа к тексту не спасает от заполнения диска изображениями.

Для каждого актива определим нормальное действие. Alice читает и изменяет собственную заметку. Boris делает то же со своей. Неавторизованный посетитель открывает форму входа, но не получает личный список. Администратор учебного стенда может подготовить базу и восстановить копию; эта возможность не передаётся обычному HTTP-запросу.

Объект Разрешённое действие Недопустимый результат
Заметка 1 Чтение и изменение alice Boris получает её текст
Пароль Проверка библиотечной функцией Значение попадает в журнал
Сессия Подтверждение действующего входа Отозванный доступ продолжает работать
Изображение Ограниченная загрузка владельцем Файл заменяет исходник приложения

Таблица задаёт требования, а не доказывает их выполнение. В конце курса каждому требованию сопоставим запрос, исходное состояние и ожидаемый ответ. Строка «доступ защищён» без такого сценария мало помогает: разные разработчики могут понимать её по-разному.

Где проходит граница доверия

Браузер пользователя является самостоятельным участником. Он может отправить запрос без нашей формы, изменить номер заметки или повторить предыдущую отправку. Проверка JavaScript полезна для удобства, но сервер не получает гарантии её выполнения. Поэтому правила доступа должны действовать в обработчике независимо от оформления страницы.

Рассмотрим путь обычного изменения:

Поле браузера → HTTP-запрос → обработчик приложения
                                     ↓
                               проверка владельца
                                     ↓
                                 база заметок
                                     ↓
                              шаблон → браузер

На каждом переходе меняется смысл данных. HTTP-параметр становится значением SQL-запроса; сохранённая строка затем попадает в HTML. Одно универсальное «очищение» не устанавливает правильный договор для всех переходов. SQL требует параметров, вывод обычного текста — соответствующего контекста, а доступ — проверки конкретного пользователя и объекта.

Внутренняя база тоже не является источником безусловно безопасного HTML. Вчера приложение могло сохранить произвольный текст, импорт мог добавить старые значения, а другой обработчик мог иметь ошибку. Именно поэтому будем выводить заметку как текст каждый раз, а не считать её безопасной после единственного сохранения.

Возможности нарушителя

Для учебной модели достаточно обычного посетителя, управляющего собственным браузером. Он знает адрес приложения, может менять параметры и имеет свою учётную запись boris. Мы не предполагаем, что у него уже есть доступ к процессу сервера или ключу подписи. Если такая предпосылка меняется, изменяется и модель защиты.

Это позволяет задать конкретные вопросы. Может ли Boris подставить номер 1 в адрес? Может ли строка заметки изменить структуру SQL? Может ли сторонняя страница заставить браузер Alice отправить изменение? Может ли загруженный файл оказаться доступным независимо от владельца? Для каждого вопроса будет отдельный механизм.

Не нужно начинать с огромного списка названий атак. Сначала возьмите одну операцию и пройдите её путь. Для изменения заметки это личность отправителя, право на объект, подлинность действия, форма текста и ограничение ресурса. Получается понятная последовательность требований, которую можно проверить на небольшом приложении.

Вероятность, последствия и приоритет

Риск связывает возможность нежелательного события с его последствиями. В учебной библиотеке чтение чужой заметки важнее косметической ошибки подписи. Но это не означает, что любая редкая проблема может быть проигнорирована: утечка ключа подписи изменит доверие ко всем сессиям сразу.

Сначала исправляем ошибки, позволяющие обойти основную границу. Отдельно рассматриваем доступность и сопровождение. Прекрасная проверка владельца не поможет, если секрет опубликован вместе с исходниками, а копию базы невозможно восстановить. У этих проблем другие причины, поэтому они получат собственные уроки.

Полезно записывать предположения. Например, приложение обслуживает только вымышленные заметки, изображения ограничены PNG, исходящие запросы имеют фиксированную цель. Если позже появятся публичные профили или импорт HTML, прежний анализ перестанет охватывать новые операции. Модель нужно обновить до добавления соответствующего маршрута.

Проверяемое требование

Переформулируем «чужие заметки защищены» точнее: запрос Boris к заметке 1 не возвращает её содержимое; изменение этой заметки также не выполняется. Проверяются оба действия. Отказ только при чтении оставил бы возможность повредить объект без просмотра.

Аналогично определим вывод текста: название с угловыми скобками отображается буквально и не создаёт новый HTML-элемент. Для SQL ожидаем поиск по заданному значению, даже если строка содержит кавычку. Для загрузки неизвестный формат отклоняется до появления доступного файла.

Принцип проверки прав каждого обращения описан в рекомендациях OWASP по авторизации. В нашей модели применим его к двум владельцам и двум объектам; конкретный сценарий понятнее общего обещания защитить приложение.

Приоритеты полезно пересматривать после изменения назначения сервиса. Пока заметки учебные, последствие утечки одно; после появления реальных личных данных оно другое. Сама таблица объектов может сохраниться, но требования к хранению и сопровождению станут строже.

Сохраните таблицу требований рядом с проектом. При изменении кода она поможет заметить потерянную границу: новый API должен проверять владельца так же, как HTML-маршрут. В следующем уроке подготовим отдельный локальный стенд, на котором эти требования получат конкретные адреса и данные.