Что такое SQL-инъекция и как от неё защититься?

Ответ

SQL-инъекция (SQL Injection) — это критическая уязвимость веб-безопасности, возникающая, когда злоумышленник может внедрить произвольный SQL-код в запросы приложения к базе данных. Причина — некорректная обработка или отсутствие валидации пользовательского ввода.

Пример уязвимого кода (PHP):

// Пользовательский ввод напрямую подставляется в запрос
$username = $_POST['username']; // Например: `admin' --`
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";
// Итоговый запрос: SELECT * FROM users WHERE username='admin' --' AND password='...'
// Комментарий `--` отменяет проверку пароля, позволяя войти как admin.

Более опасный пример — удаление данных:

Ввод: `'; DROP TABLE users; --`
Запрос: SELECT * FROM users WHERE username=''; DROP TABLE users; --' ...

Методы защиты:

  1. Использование подготовленных выражений (Prepared Statements) с параметризованными запросами — самый эффективный способ.
    // Java (JDBC) пример
    String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
    PreparedStatement stmt = connection.prepareStatement(sql);
    stmt.setString(1, username); // Данные безопасно "привязываются"
    stmt.setString(2, password);
    ResultSet rs = stmt.executeQuery(); // Внедрение невозможно
  2. Использование ORM (Hibernate, Entity Framework) — они генерируют параметризованные запросы.
  3. Экранирование специальных символов (менее надежно, чем prepared statements).
  4. Принцип минимальных привилегий: Учётная запись БД для приложения должна иметь только необходимые права (никакого DROP, DELETE без необходимости).
  5. Валидация и санитизация ввода: Проверка данных по белому списку допустимых символов.

Для тестировщика (QA): Проверка на SQLi входит в пентест. Используются инструменты вроде sqlmap или ручная подстановка payloads (', ' OR '1'='1, '; SLEEP(5)--) в поля форм и параметры URL.

Ответ 18+ 🔞

Э, слушай, а вот эта ваша SQL-инъекция — это же просто пиздец, а не уязвимость! Представь себе, сидит какой-нибудь школоло с анонимной маски, и через простую форму логина может твою базу данных к херам разнести. А всё почему? Потому что ленивые прогеры, блядь, не хотят нормально данные обрабатывать!

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

$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";

Ну что за манда с ушами? Если я в поле логина введу admin' --, то запрос превратится в: SELECT * FROM users WHERE username='admin' --' AND password='...' Видишь? Два дефиса — это комментарий в SQL! Всё, что после них, хуй с горы, отрубается. И пароль уже не проверяется! Я как admin зашёл, блядь! Вообще ебушки-воробушки, как это просто!

А это что, цветочки? Нет, это ягодки! А вот тебе ядрёна вошь:

Ввод: '; DROP TABLE users; -- И запрос становится: SELECT * FROM users WHERE username=''; DROP TABLE users; --' ... Бабах — и таблицы users больше нет! Всё, пиздец, пользователи накрылись медным тазом. И кто потом будет восстанавливать? Правильно, не тот, кто эту хуйню написал!

Так как же, спрашивается, не быть мудаком? Защищайся, блядь!

Способ первый, и он главный — подготовленные выражения (Prepared Statements). Это как если бы ты не сам строку клеил из кусков, а дал базе данных шаблон с дырками, а потом отдельно, безопасно, эти дырки заполнил. Внедрить что-то — физически невозможно, потому что данные и команда разделены. Вот, смотри на Java:

String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, username); // Вот тут данные "привязываются"
stmt.setString(2, password);
ResultSet rs = stmt.executeQuery(); // И никакой инъекции, ёпта!

Способ второй — ORM (типа Hibernate). Они сами, эти хитрожопые фреймворки, под капотом готовят запросы. Но тут надо не расслабляться, а то и на ORM можно наступить.

Ну и остальное по мелочи:

  • Принцип минимальных прав: Зачем твоему приложению-читалке право на DROP TABLE? Да низачем! Дай аккаунту в БД только SELECT, INSERT, UPDATE и всё.
  • Валидация: Если в логине должны быть только буквы-цифры — отсекай всё остальное нахуй сразу.

А для тестировщиков, мои любимые искатели дыр: Ваша работа — тыкать во все дыры. В каждое поле, в каждый параметр URL лезьте со своими ', ' OR '1'='1, '; SLEEP(5)--. Если сайт завис на пять секунд после SLEEP — поздравляю, вы нашли пиздопроебибну! Можно запускать sqlmap и доводить дело до логического конца.

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