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

Ответ

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

Успешная атака может привести к утечке, изменению или удалению данных, а в некоторых случаях — к полному захвату контроля над сервером.

Пример уязвимости (Python):

Предположим, есть код для поиска пользователя по имени. Ввод от пользователя напрямую конкатенируется со строкой запроса.

# НЕБЕЗОПАСНЫЙ КОД!
user_input = "' OR '1'='1' -- " # Ввод злоумышленника

query = f"SELECT * FROM users WHERE name = '{user_input}';"
# cursor.execute(query)

Итоговый SQL-запрос будет выглядеть так:

SELECT * FROM users WHERE name = '' OR '1'='1' -- ';

Условие OR '1'='1' всегда истинно, поэтому запрос вернет всех пользователей из таблицы. -- комментирует оставшуюся часть запроса.

Как защититься?

Основной принцип защиты — разделение кода и данных. Данные, полученные от пользователя, никогда не должны интерпретироваться как часть исполняемого SQL-кода.

  1. Использование параметризованных запросов (Prepared Statements) Это самый надежный метод. Драйвер базы данных сам безопасно подставляет значения в запрос, экранируя все спецсимволы.

    # БЕЗОПАСНЫЙ КОД
    user_input = "' OR '1'='1' -- "
    
    # Знак '?' — это плейсхолдер для данных
    query = "SELECT * FROM users WHERE name = ?;"
    cursor.execute(query, (user_input,))
  2. Использование ORM (Object-Relational Mapping) Библиотеки вроде SQLAlchemy (Python), Hibernate (Java) или Eloquent (PHP) по умолчанию используют параметризованные запросы, что значительно снижает риск инъекций.

  3. Принцип наименьших привилегий Пользователь базы данных, от имени которого приложение выполняет запросы, должен иметь только необходимые ему права. Например, ему не нужен доступ на удаление таблиц (DROP TABLE).

Ответ 18+ 🔞

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

Представь себе, сидит приложение, тупое как пробка, и спрашивает: «Как тебя зовут, дружок?» А ты ему в ответ: «А зовут меня — ВЫВЕДИ ВСЕХ ПОЛЬЗОВАТЕЛЕЙ, СУКА!». И оно, ебать мои старые костыли, так и делает! Пиздец, а не безопасность.

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

# НЕБЕЗОПАСНЫЙ КОД! ПИЗДЕЦ КАКОЙ!
user_input = "' OR '1'='1' -- " # Вот эта хуйня от пользователя

query = f"SELECT * FROM users WHERE name = '{user_input}';"
# cursor.execute(query)

И что получается? А получается, что запрос превращается в такую дичь:

SELECT * FROM users WHERE name = '' OR '1'='1' -- ';

Видишь подвох? '1'='1' — это всегда правда, ёпта! А двойной дефис -- — это комментарий в SQL, он всё остальное в запросе отрубает. В итоге эта конструкция вывалит на тебя всю таблицу users, как из ведра! Удивление пиздец, да? А если повезёт, то и пароли тоже.

Ну и как от этого спастись, спросишь ты?

А главное правило — не мешай говно с конфетами! Данные от пользователя — это одно, а команды SQL — это совсем другое. Их нужно держать в разных комнатах, а лучше — в разных городах.

  1. Параметризованные запросы (Prepared Statements) Это святое, блядь! Ты говоришь базе: «Слушай, вот у меня будет запрос, а вот тут — дырка для значения». А потом отдельно, с поклоном, подсовываешь туда пользовательский ввод. База данных сама всё грамотно экранирует, и никакая инъекция не пролезет.

    # БЕЗОПАСНЫЙ КОД. ВСЁ ЧИСТО.
    user_input = "' OR '1'='1' -- " # Пусть себе вводит, похуй!
    
    # Вопросительный знак — это та самая дырка, плейсхолдер
    query = "SELECT * FROM users WHERE name = ?;"
    cursor.execute(query, (user_input,)) # А вот сюда аккуратненько подкладываем значение

    Теперь база воспримет этот ввод не как команду, а просто как странную строку для поиска. И никого не найдёт. Идеально.

  2. Использование ORM (Object-Relational Mapping) Это для ленивых, но умных. Берёшь библиотеку типа SQLAlchemy, и она за тебя всё делает. Ты там с объектами работаешь, а она сама генерит безопасные запросы. Красота, блядь.

  3. Принцип наименьших привилегий А это, понимаешь, стратегическая хитрость. Зачем давать приложению права бога и творца в базе данных? Пусть у него будет ровно столько прав, сколько нужно для работы: читать из своей таблицы, писать в неё — и всё. Никаких DROP TABLE, никаких прав на системные таблицы. Пусть даже если его и взломают, ущерб будет локальным, а не тотальным. Хитрая жопа, но работает.

Вот и вся наука. Не доверяй пользовательскому вводу, блядь, никогда! Он всегда, сука, окажется злобнее и хитрее, чем ты думаешь.