![]() |
SQL Injection: современные методы защиты сайта — кто сталкивался?
SQL Injection — одна из самых распространённых и опасных уязвимостей в веб-приложениях, с которой рано или поздно сталкивался почти каждый, кто хоть немного работает с разработкой сайтов или поддержкой. Если по-простому — это когда кто-то вписывает в форму или адресную строку вашего сайта кусок SQL-кода, который ломает логику запросов к базе данных и позволяет получить то, чего не должно быть видно или доступно. Тут можно не только украсть данные, но и сломать сайт, изменить что-то в базе, а иногда и получить полный контроль над сервером. Разберёмся в деталях, как это работает, как с этим бороться и на что обращать внимание.
Что такое SQL Injection SQL Injection (SQLi) — это когда злоумышленник вставляет в поля ввода или в параметры запроса специально подготовленные SQL-команды, которые выполняются вместе с основным запросом к базе данных. В итоге он может вытащить списки паролей, записей, изменить информацию или даже удалить базы. Чаще всего это происходит из-за неправильной обработки пользовательских данных, когда ввод никак не фильтруется и напрямую включается в строку SQL-запроса. Вспомните классический пример: есть форма логина, куда вводится имя пользователя и пароль. Если эти данные подставляются напрямую в SQL в виде: SELECT * FROM users WHERE login = '$login' AND pass = '$pass'; и $login или $pass — это то, что написал посетитель сайта, то он может придумать, например, такую "команду": admin' OR '1'='1 И тогда запрос превратится в: SELECT * FROM users WHERE login = 'admin' OR '1'='1' AND pass = '...'; Из-за того что '1'='1' — всегда правда, запрос вернёт данные администратора, и авторизация пройдёт без пароля. Где чаще всего встречается проблема SQLi — не какая-то редкая проблема, а скорее классика жанра. В основном она появляется в сайтах: - Которые прямо собирают SQL-запросы через конкатенацию строк, без использования подготовленных выражений (prepared statements). - В самописных движках и скриптах, где нет нормальной абстракции для базы данных. - В старых CMS, которые не обновлялись и не исправляли свои баги. - В формах логина, регистрации, обратной связи, поисках, фильтрах, где ввод пользователя напрямую влияет на запрос. - На сайтах на PHP, Python, Node.js и других, где программисти не используют методы безопасности. Обратите внимание: проблема не в языке программирования, а в подходе к построению запросов и проверке данных. Как выглядит атака на примерах Допустим, у вас есть такой PHP-код: $sql = "SELECT * FROM users WHERE login='$login' AND pass='$pass'"; Если в поле логина написать: admin' -- то запрос превратится в: SELECT * FROM users WHERE login='admin' -- ' AND pass='...'; Соответственно, всё после -- игнорируется как комментарий, и проверка пароля не сработает. Другой пример — поиск товара: $sql = "SELECT * FROM products WHERE category='$category'"; Если туда отправить: electronics' UNION SELECT username, password FROM users -- то вы сможете получить данные из таблицы users. Примеры на практике — как защититься 1. Используйте подготовленные выражения (prepared statements) с параметризацией — это самый надёжный способ. Так данные пользователя не вставляются напрямую в строку запроса, а передаются как параметры, и база не воспринимает их как часть SQL. 2. Фильтруйте и валидируйте ввод. Например, если ожидается число — проверяйте его тип и диапазон, если строка — ограничьте разрешённые символы. 3. Проще и надежнее — использовать ORM или уже готовые библиотеки, которые сами заботятся о безопасности. 4. Минимизируйте права пользователя базы. Сделайте так, чтобы веб-приложение имело только те права, которые ему абсолютно нужны — если запрос только читает данные, то пусть пользователь не сможет удалять или менять записи. 5. Подключайте веб-аппликационный firewall (WAF) — хотя это не заменяет правильное программирование, но помогает отловить известные атаки. 6. Обязательно обновляйте свой движок и библиотеки — прикрученные патчи исправляют старые дырки. Типичные ошибки при защите от SQLi - Использование функций типа addslashes() или manual escaping — мало помогает, да и устаревший метод. - Полагаться только на фильтрацию без параметризированных запросов. - Не понимать, что SQLi — это не только форма логина, а любые места, где куда-то можно передать данные. - Пропускать проверки на стороне сервера и слепо доверять клиенту. - Игнорировать ошибки базы, которые могут выдать подсказку хакеру. - Давать приложению слишком широкие права в базе. Чек-лист защиты от SQL Injection - [ ] Все SQL-запросы используют подготовленные выражения. - [ ] Ввод проверяется и валидируется на стороне сервера. - [ ] Права пользователя базы сведены к минимуму. - [ ] В приложении нет конкатенации пользовательских данных с SQL. - [ ] Логи ошибок базы ограничены, и в них не отображаются исходные запросы. - [ ] Используется WAF с актуальными правилами. - [ ] Регулярно обновляются CMS, фреймворки и библиотеки. - [ ] Проведён аудит кода на предмет уязвимостей SQL Injection. - [ ] Используются дополнительные методы защиты — например, хэширование паролей, чтобы в случае взлома база была бесполезна для хакера. FAQ по SQL Injection - Можно ли полностью исключить SQLi? Почти да, если все запросы сделаны через подготовленные выражения и код проверен. Но всегда полезно совмещать несколько уровней защиты. - Что делать, если сайт уже взломали через SQLi? Первым делом — оценить, какие данные могли быть скомпрометированы, закрыть уязвимость, поменять доступы в базу, проверить логи, и, если нужно, обратиться к специалистам по безопасности. - Можно ли обнаружить SQLi с помощью автоматических сканеров? Да, сканеры помогают, но не гарантируют стопроцентное обнаружение. Лучше и код постоянно ревьюить, и тестировать ручными методами. - Подходит ли ORM за защиту от SQLi? ORM в большинстве случаев автоматом делают подготовленные запросы, но никто не стоит над душой и не запретит программисту написать уязвимый нативный запрос, так что будьте внимательны. - Есть ли смысл закрывать SQLi на уровне HTTP-заголовков или через .htaccess? Нет, такие методы не помогают защититься от реальной уязвимости в коде, максимум могут фильтровать какие-то банальные атаки. *** Делитесь своим опытом, кто как защищал сайты? Есть ли какие-то нестандартные решения или случаи, когда SQLi неочевидно проходил? Может, кто-то ещё сталкивался с багами старых CMS и как их патчил? Обсудим. |
Я в целом сомневаюсь, что простая фильтрация и проверка типов полностью спасет от SQLi. Особенно если где-то в коде заваляется старый запрос с прямой конкатенацией. Тут нужен именно комплексный подход и старания от всей команды, иначе можно так долго биться, а дырка всё равно найдётся. Параметризованные запросы вроде должны быть базой, но на практике часто забывают.
|
| Время: 09:13 |