Чем опасны SQL-инъекции и как от них защититься
Утечки паролей и платежной информации из базы данных, серьезные сбои в работе веб‑приложений — вот некоторые из результатов SQL‑инъекций (англ. SQL injection, SQLi). Жертвами злоумышленников становятся даже компании, которые уделяют внимание вопросам кибербезопасности, а также их партнеры и клиенты.
Яркий пример — атака на IT‑компанию Kaseya в июле 2021 года. Киберпреступники обошли аутентификацию, загрузили на VSA‑сервер полезную нагрузку и использовали SQL‑инъекцию для развертывания вредоносных обновлений. В результате больше 36 тысяч поставщиков услуг не могли получить доступ к флагманскому сервису Kaseya VSA в течение как минимум четырех дней. Простой привел к значительным убыткам.
А в июне 2023 года больше 200 компаний и учреждений столкнулись с атаками из‑за уязвимости к SQL‑инъекциями в программе передачи файлов MOVEit от Progress Software. Злоумышленники получили доступ к файлам и учетным данным. Среди жертв — школы в США, университеты по всему миру, а еще такие компании, как BBC, Boots и British Airways. Всего от утечек пострадали 17–20 млн человек.
Чем еще опасны SQL‑инъекции, как они работают и какие меры защиты помогут им противостоять, расскажем в статье.
SQL‑инъекция — это атака с внедрением вредоносного кода SQL в веб‑приложение. Злоумышленник вводит в форму запроса или добавляет прямо в URL‑адрес специально сформированный SQL‑код, который исполняется на сервере. Введенный код позволяет получить доступ к базе данных (англ. database, далее — БД) и выполнять различные операции, от просмотра до уничтожения БД. Для этого киберпреступники используют язык запросов SQL.
SQL (Structured Query Language) — самый популярный язык для работы с реляционными БД (например, MySQL или PostgreSQL). SQL позволяет взаимодействовать с объектами в БД, а также выполнять запросы и анализировать данные.
Основные операторы (команды SELECT, INSERT, UPDATE и DELETE) нужны, чтобы получать, добавлять, изменять и удалять данные из таблиц.
Команда SELECT
Используется в SQL для выбора данных из одной или нескольких таблиц в БД. SELECT позволяет извлекать информацию на основе определенных условий и критериев.
Примеры:
SELECT * FROM table_name;
Эта команда извлекает из таблицы table_name все столбцы и строки, на что указывает звездочка (*).
SELECT * FROM users WHERE username = 'admin' OR 1=1;
В этом случае команда SELECT используется с оператором OR, служащим для создания условия, которое всегда будет верным (1=1). Таким образом запрос вернет все записи из таблицы, а не только записи, соответствующие условию username = 'admin'. Обратите внимание на синтаксис: числовые значения указываются без кавычек, а для строковых кавычки добавляются.
SELECT * FROM users WHERE username = 'admin' ORDER BY password;
В этом запросе используется команда ORDER BY для сортировки результатов по столбцу password.
Команда INSERT
Нужна, чтобы добавлять новые строки данных в таблицу БД.
Примеры:
INSERT INTO table_name (column1, column2, column3)
VALUES (value1, value2, value3);
Команда добавляет новую строку данных в таблицу table_name. В скобках указываются названия столбцов таблицы, в которые будут добавлены новые значения. Затем в строке с ключевым словом VALUES вписываются значения для каждого столбца.
INSERT INTO users (username, password) VALUES ('admin', 'password') TO 'user@example.com';
Этот запрос вставляет строку в таблицу users с именем пользователя admin и паролем password. Результат с помощью ключевого слова TO будет отправлен на указанный email.
Команда UPDATE
Применяется в SQL для обновления данных в таблице БД, позволяя изменять значения в одном или нескольких столбцах.
Примеры:
UPDATE table_name
SET column1 = new_value1, column2 = new_value2
Код меняет данные в строке с ключевым словом SET в таблице table_name. Указываются столбцы, которые нужно обновить, и новые значения для каждого из них.
UPDATE users SET password = 'new_password' WHERE username IN ('admin', 'guest');
Запрос с помощью ключевых слов SET, WHERE и IN обновляет пароли записей, у которых имя пользователя — admin или guest.
Команда DELETE
Позволяет удалить одну или несколько строк из таблицы в БД.
Примеры:
DELETE FROM table_name
WHERE some_column = some_value;
Команда удаляет строки из таблицы table_name. В строке с ключевым словом WHERE указывается условие, определяющее, какие строки нужно удалить.
DELETE FROM users WHERE password = NULL;
Ключевое слово NULL позволяет удалить записи, у которых не установлен пароль.
Все эти команды злоумышленники используют для создания вредоносных запросов.
SQL-инъекции используют уязвимости в системе безопасности приложений для внедрения вредоносного кода в базу данных. Но реализовать такие атаки можно по‑разному. Выбор способа в основном зависит от цели атаки и наличия определенных недочетов в защите приложения, например отсутствия фильтрации пользовательского ввода. Также на выбор вида атаки влияют знания и опыт злоумышленника. Опытный киберпреступник может использовать более сложные методы, такие как вызов ошибок.
Вот наиболее распространенные виды SQLi:
- Атака на авторизацию. Используется, чтобы обойти систему авторизации, получить доступ к защищенным данным или изменить привилегии.
- Error‑based SQL‑инъекция. Помогает получить информацию обо всей БД и извлечь хранящиеся в ней данные, просматривая ошибки в работе вызываемых функций.
- Слепая SQL‑инъекция. Применяется, когда не удается определить успешность выполнения кода по сообщениям об ошибке. Слепая SQL‑инъекция позволяет анализировать ответы БД на вредоносные запросы по косвенным признакам, например по длине ответа (количество символов) от веб‑приложения.
- Time‑based SQL‑инъекция. Позволяет узнать об успешно выполненной инъекции на основе времени ответа от сервера: это указывает, истинный (true) результат опроса или ложный (false).
- UNION‑атака. Извлекает данные сразу из нескольких таблиц БД при помощи оператора UNION, который объединяет результаты двух или более SELECT‑запросов и возвращает их.
- Out-of-band SQL‑инъекция. Используется, если сервер способен генерировать запросы DNS или HTTP. По этим запросам злоумышленник собирает информацию о базе данных. Out-of-band SQLi также называют внеполосной инъекцией.
А теперь рассмотрим механизм реализации и конкретные примеры SQLi.
SQL‑инъекция обычно осуществляется в три этапа:
- Поиск веб‑приложений, которые используют запросы SQL для работы с БД.
- Исследование этих приложений для обнаружения уязвимых точек, где может быть внедрен код SQL. Как правило, уязвимыми оказываются поля, куда пользователи вводят регистрационные данные, чаще всего логин и пароль.
- Ввод сформированного SQL‑кода в форму запроса или параметр URL, который передается на сервер БД. Если сервер БД не защищен от SQLi, код SQL успешно выполняется, так что взломщики получают доступ к базе данных и могут проводить любые операции.
Вот несколько примеров, которые помогут лучше понять принцип работы этой атаки.
SQLi с использованием оператора SELECT
Допустим, веб-форма запрашивает у пользователя логин и пароль для входа в систему. При вводе в БД отправляется запрос вида:
SELECT id FROM users
WHERE username = 'username' AND password = 'password'
Если приложение не проверяет пользовательский ввод на наличие вредоносного кода, злоумышленник получает возможность использовать SQL‑инъекцию. Например, вводит такой SQL‑запрос:
SELECT id FROM users
WHERE username = 'administrator' -- AND password = ' '
Двойной дефис (--) используется для комментирования оставшейся части запроса, чтобы она не выполнялась. Результат — злоумышленник получает доступ к учетной записи администратора без ввода пароля.
SQLi с использованием оператора UPDATE
Пример актуален для приложений, в которых пользователям разрешено менять пароль. Изначально запрос SQL выглядит так:
UPDATE users SET password = 'new_pass' WHERE id = 35;
Это запрос на смену пароля пользователем с идентификационным номером 35 в строке таблицы базы данных.
Те же самые два дефиса (--), обозначающие в SQL начало комментария, позволяют злоумышленнику изменить пароль на new_pass сразу для всех пользователей. В этом случае БД проигнорирует фрагмент с условием (WHERE id = 35;):
UPDATE users SET password = 'new_pass' -- WHERE id = 35;
SQLi с использованием оператора UNION (UNION‑атака)
Представим, что веб‑приложение принимает определенный параметр (в данном случае id, идентификационный номер строки) через URL‑адрес и использует его для построения SQL‑запроса:
SELECT * FROM users WHERE id = '1';
Если приложение уязвимо к SQL-инъекции, злоумышленник внедрит свой код SQL в параметр id:
SELECT * FROM users WHERE id = '1' UNION SELECT 1,username,password,4,5 FROM another_table -- -';
Это позволит атакующему получить данные из таблицы another_table, содержащей имена пользователей и пароли.
Из примеров видно, что SQL‑инъекции могут привести к серьезным последствиям, например к потере контроля над системами, несанкционированному доступу к чувствительной информации или нарушению целостности данных. Угроза до сих пор актуальна, поэтому так важно понимать, как работают SQLi и каким образом можно защититься от них.
Лучшее средство противодействия любым киберинцидентам — профилактика. Вот что поможет защитить сайт или веб‑приложение от атак с внедрением SQL‑кода:
- Проверка входных данных. Позволяет автоматически удалять потенциально опасный код из SQL‑запросов. Такая проверка реализуется через фильтрацию ввода в веб‑формах и URL. Сюда же отнесем белые списки, которые разрешают приложению использовать только определенные типы входных данных: например, целочисленные значения в URL‑параметрах.
- Параметризованные запросы. Обеспечивают передачу входных данных (имя пользователя или пара «логин — пароль») отдельно от самого кода, то есть данные не вставляются в запрос напрямую. И поскольку параметры посылаются только во время выполнения, внедрение в запросы вредоносного кода через SQL становится невозможным. Параметризованные запросы, также называемые подготовленными выражениями, нередко реализуются через язык веб‑программирования PHP.
- Встроенные функции фреймворков. Помогают составлять SQL‑запросы безопасно. Функции валидации проверяют типы данных, длину строк и другие характеристики, а также применяют фильтры, чтобы удалять или экранировать небезопасные символы.
- Ограничение прав доступа. Предполагает использование принципа наименьших привилегий, чтобы только определенные пользователи могли выполнять важные операции в БД.
- Регулярные обновления ПО. Позволяют избавиться от уязвимостей, которые обнаружили и исправили разработчики.
- Межсетевой экран. Использует списки сигнатур (уникальные описания вредоносного кода), характеризующих опасные векторы атак. Это позволяет оперативно блокировать подозрительные SQL‑запросы.
- Обучение сотрудников кибербезопасности. Делает компанию и ее продукты более устойчивыми к действиям злоумышленников. Разработчики и сотрудники, занимающиеся поддержкой веб‑приложений, должны знать о различных типах кибератак (в том числе и об SQLi), понимать важность обновления ПО, использовать методы безопасной разработки, применять ограничения прав доступа.
- Проверка на наличие уязвимостей. Дает возможность выявлять и устранять потенциальные уязвимости до того, как их обнаружат злоумышленники. Обычно применяют тестирование на проникновение (пентесты), анализ защищенности приложений или постоянное сканирование внешнего периметра (CPT).
Эти меры не гарантируют полную защиту от атак с помощью SQL‑инъекций, но помогут минимизировать вероятность успеха злоумышленников, а еще уменьшить потери, если инцидент все же произойдет.