Перейти к содержанию
Educora
Продвинутый20 мин6 / 12

Веб-безопасность: OWASP Top 10

Изучи самые критичные риски веб-приложений: SQL-инъекции и параметризованные запросы, XSS и экранирование, CSRF, ошибки аутентификации и заголовки безопасности.

Проверь себя
В этом уроке ты узнаешь
  • Узнавать категории OWASP Top 10 и объяснять каждую на примере
  • Исправлять уязвимый SQL-код с помощью параметризованного запроса
  • Предотвращать XSS экранированием вывода
  • Выбирать защиту от CSRF и основные заголовки безопасности

Эльвин написал свой первый сайт: страница входа, комментарии, профиль. Для честных пользователей всё работает идеально. Веб-безопасность задаёт другой вопрос: что будет, если пользователь пришлёт что-то неожиданное? Ответы на этот вопрос годами собирает в свой список сообщество OWASP.

OWASP Top 10

КодКатегорияПример
A01Нарушение контроля доступасмена номера заказа в URL открывает чужой заказ
A02Криптографические ошибкичувствительные данные передаются или хранятся без шифрования
A03Внедрение (инъекции)текст пользователя выполняется как SQL или команда; сюда же относится XSS
A04Небезопасный дизайнвосстановление пароля держится только на вопросе «любимый цвет»
A05Ошибки конфигурациистандартные пароли администратора, подробные тексты ошибок для пользователей
A06Уязвимые и устаревшие компонентыверсия библиотеки с известной уязвимостью
A07Ошибки идентификации и аутентификациинет ограничения на число попыток входа
A08Нарушения целостности ПО и данныхобновления ставятся без проверки подписи
A09Недостатки журналирования и мониторингаатака месяцами остаётся незамеченной
A10Подделка запросов на стороне сервера (SSRF)сервер обращается по URL от пользователя к внутреннему сервису
Издание 2021 года. OWASP обновляет список раз в несколько лет — актуальную версию смотри на owasp.org.

Инъекции: когда данные становятся кодом

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

Уязвимо: склейка строк
def find_user(conn, username):
    query = "SELECT id, email FROM users WHERE username = '" + username + "'"
    return conn.execute(query).fetchall()
Безопасно: параметризованный запрос
def find_user(conn, username):
    query = 'SELECT id, email FROM users WHERE username = ?'
    return conn.execute(query, (username,)).fetchall()
? — это заполнитель: драйвер передаёт значение отдельно, поэтому кавычки в значении не могут изменить структуру запроса.
Python
import sqlite3

conn = sqlite3.connect(':memory:')
conn.execute('CREATE TABLE users (id INTEGER, username TEXT)')
conn.executemany('INSERT INTO users VALUES (?, ?)', [(1, 'aysel'), (2, "o'neil")])

name = "o'neil"   # a real surname with an apostrophe
try:
    conn.execute("SELECT id FROM users WHERE username = '" + name + "'").fetchall()
except sqlite3.OperationalError as error:
    print('String building failed:', error)

rows = conn.execute('SELECT id FROM users WHERE username = ?', (name,)).fetchall()
print('Parameterised query:', rows)
▸ Ожидаемый результат
String building failed: near "neil": syntax error
Parameterised query: [(2,)]
Даже без всякой атаки настоящий пользователь с апострофом в фамилии ломает склеенный запрос. Значит, та же дверь открыта и для злоумышленника.

XSS: чужой скрипт в браузере

Межсайтовый скриптинг (XSS) возникает, когда текст пользователя вставляется в страницу без экранирования и браузеры других посетителей выполняют его как код. Такой скрипт может украсть сессионную cookie или совершать действия от имени жертвы. Защита: экранировать вывод с учётом контекста (шаблоны с автоэкранированием), заголовок Content-Security-Policy и cookie с флагом HttpOnly.

Python
import html

comment = "<script>alert('hi')</script> Nice lesson!"
print('Raw:    ', comment)
print('Escaped:', html.escape(comment))
▸ Ожидаемый результат
Raw:     <script>alert('hi')</script> Nice lesson!
Escaped: &lt;script&gt;alert(&#x27;hi&#x27;)&lt;/script&gt; Nice lesson!
Экранированный текст выглядит на странице так же, но браузер показывает его как обычный текст, а не как тег.

CSRF и ошибки аутентификации

CSRF (межсайтовая подделка запроса): пользователь вошёл в интернет-банк, затем открыл другой сайт, а тот тайно отправил в банк форму. Браузер автоматически прикладывает cookie банка, и запрос выполняется от имени жертвы. Защита: случайный анти-CSRF-токен в каждой форме с проверкой на сервере, cookie с SameSite=Lax или Strict, проверка заголовка Origin и повторное подтверждение важных действий.

Ошибки аутентификации — это отсутствие ограничения на число попыток (именно так работает массовая проверка утёкших паролей), разрешение слабых паролей, неизменный идентификатор сессии после входа и незавершённая сессия при выходе. Лекарство: ограничение частоты запросов, MFA, cookie с Secure и HttpOnly, новая сессия после входа.

Заголовки безопасности

ЗаголовокЧто делает
Content-Security-Policyзадаёт, откуда можно загружать скрипты, стили и изображения, — второй барьер против XSS
Strict-Transport-Securityвелит браузеру открывать сайт только по HTTPS (HSTS)
X-Content-Type-Options: nosniffзапрещает браузеру «угадывать» тип файла
X-Frame-Options / frame-ancestorsне даёт встроить сайт в скрытый фрейм на чужой странице (кликджекинг)
Set-Cookie: Secure; HttpOnly; SameSitecookie передаётся только по HTTPS, недоступна скриптам и не прикладывается к запросам с чужих сайтов
Задание

Напиши escapeHtml(text): функция должна заменять &, <, >, " и ' соответственно на &amp;, &lt;, &gt;, &quot; и &#39;. Внимание: & нужно заменять первым.

Задание · JavaScript
function escapeHtml(text) {
  // replace & first, then < > " '
  return text;
}

console.log(escapeHtml('Tom & Jerry'));
console.log(escapeHtml('<b>bold</b>'));
console.log(escapeHtml(`<img src="x" alt='y'>`));
console.log(escapeHtml('&lt;'));
▸ Ожидаемый результат
Tom &amp; Jerry
&lt;b&gt;bold&lt;/b&gt;
&lt;img src=&quot;x&quot; alt=&#39;y&#39;&gt;
&amp;lt;

Главное

  • OWASP Top 10 — список самых критичных рисков веб-приложений; на первом месте нарушение контроля доступа.
  • Единственное надёжное средство от SQL-инъекций — параметризованные запросы.
  • Против XSS вывод экранируют по контексту, а CSP создаёт второй барьер.
  • От CSRF защищают анти-CSRF-токены и cookie с SameSite.
  • Заголовки безопасности (CSP, HSTS, nosniff, frame-ancestors) — дешёвая, но сильная защита.

Проверь себя

Вопросов: 10. Каждый правильный ответ приносит XP.

1 / 10
Пользователь меняет в URL order=1001 на order=1002 и видит чужой заказ. Какая это категория?