Безопасность
CSRF: собери эксплойт, потом защиту
Читать про CSRF — не то же самое, что увидеть, как подделанный запрос двигает реальные деньги на твоей машине. Собери небольшое приложение на сессионных куках, напиши атакующую страницу, которая его эксплуатирует, затем добавляй защиты юнита слой за слоем — доказывая, что каждый эксплойт умирает по ходу.
Преврати ментальную модель юнита в воспроизводимый цикл: подними уязвимую цель, продемонстрируй работающий CSRF, затем слой за слоем добавь SameSite, токен-защиту и проверку Origin, проверяя после каждого слоя, что подделанный запрос падает по правильной причине.
Собрать намеренно уязвимое к CSRF приложение на сессионных куках и отдельный атакующий origin, проэксплуатировать его end-to-end, затем закалить SameSite, CSRF-токеном и проверкой Origin — доказав реальной кросс-ориджин атакующей страницей, что каждый задокументированный вектор падает после закалки.
- Лог эксплойтов до/после: для каждого вектора (кросс-сайтовый POST, побочный эффект на GET, login CSRF) покажи его успех до закалки и падение после, с ответом/статусом сервера как доказательством — наблюдаемым, а не утверждённым.
- Матрица защит, сопоставляющая каждый вектор слою, который его останавливает (SameSite, токен, перенос GET в POST, проверка Origin), с пометкой, какие слои — избыточный defense-in-depth, а какой — несущий.
- Показано, что токен-защита отвергает подделанный запрос, опускающий или угадывающий токен, и принимает легитимный same-origin запрос — оба продемонстрированы, а не заявлены.
- Абзац-разбор, объясняющий, почему одного SameSite было недостаточно и какой единственный слой был бы минимально достаточной защитой, если бы можно было оставить только один.
- Продемонстрируй обход SameSite: проэксплуатируй изменение состояния на GET под SameSite=Lax через top-level навигацию и (если браузер это даёт) окно ~120с default-Lax Lax+POST сразу после логина.
- Сломай собственную обычную double-submit защиту, сымитировав запись куки атакующим (например, сиблинг-поддомен), затем почини, переключившись на HMAC-подписанный вариант, привязанный к сессии, и покажи, что эксплойт умирает.
- Добавь JSON API маршрут, защищённый только требованием кастомного заголовка + непростого content-type (preflight), затем покажи с origin B, что подделанный кросс-сайтовый fetch не удовлетворяет preflight — и объясни, почему top-level POST-форма всё ещё обошла бы это, если бы маршрут принимал form-кодировку.
- Напиши короткую заметку по threat-model: перечисли каждый эндпоинт изменения состояния, его метод, его опору на SameSite и покрытие токеном, и пометь любой маршрут, где падение одного слоя снова открыло бы дыру.
Это цикл, который ты гоняешь, защищая любое приложение на сессионных куках: собери уязвимую версию, докажи эксплойт на своей машине, затем слой за слоем добавляй защиты и проверяй, что каждый подделанный запрос падает по правильной причине. SameSite=Lax убивает кросс-сайтовый POST, но оставляет побочные эффекты на GET и бреши None/login-CSRF; реальная токен-защита (synchronizer для stateful, HMAC double-submit для stateless) — несущий слой; перенос мутаций с GET и проверка Origin/Referer — defense-in-depth, ловящий то, что проскальзывает. Сделав это раз против своей атакующей страницы, ты доводишь production-постуру до мышечной памяти.