company_banner

Первое знакомство с SQL-инъекциями

Автор оригинала: A. Boukar
  • Перевод
SQL-инъекции (SQL injection, SQLi, внедрение SQL-кода) часто называют самым распространённым методом атак на веб-сайты. Их широко используют хакеры и пентестеры в применении к веб-приложениям. В списке уязвимостей OWASP Топ-10 присутствуют SQL-инъекции, которые, наряду с другими подобными атаками, находятся на первом месте среди угроз, с которыми сталкиваются веб-проекты.

Несмотря на то, что SQL-инъекции существуют уже более 20 лет, этот метод атаки на веб-проекты всё ещё можно успешно применить для взлома тех веб-сайтов и приложений, создатели которых не реализовали в них соответствующие защитные механизмы.



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

Реляционные базы данных


Прежде чем говорить о SQL (и о SQL-инъекциях), нам надо познакомиться с реляционными базами данных (БД).

В реляционной БД хранятся взаимосвязанные данные, которые часто размещаются в таблицах. Каждая таблица содержит набор столбцов и строк.

Вот, например, таблица, которая называется users.


Таблица users

Эта таблица содержит три столбца (их ещё называют атрибутами): Id, User, Password. Строки таблицы называют записями. В нашей таблице имеется две записи.

Беглый взгляд на эту таблицу позволяет сделать вывод о том, что в ней, вероятно, хранятся учётные данные пользователей некоей системы. После того, как пользователь вводит имя и пароль в форме аутентификации, веб-приложение сверяет эти данные с вышеприведённой таблицей. Именно после того, как данные пользователя найдены (или не найдены) в таблице, приложение узнаёт о том, следует ли, например, дать этому пользователю возможность работать с ресурсами проекта, предназначенными только для зарегистрированных пользователей.

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

На этом мы закончим разговор о реляционных базах данных, так как этого достаточно для того чтобы разобраться в том, о чём речь пойдёт дальше.

SQL


SQL (Structured Query Language, язык структурированных запросов) — это язык, который предназначен для работы с реляционными БД. С его помощью, взаимодействуя с базой данных, можно просматривать, добавлять, обновлять, удалять данные.

▍Основные SQL-выражения


Веб-приложение взаимодействует с базой данных, пользуясь SQL-выражениями. Каждое такое выражение начинается с некоей команды.

Вот пример, который поможет нам разобраться в синтаксисе подобных выражений:

SELECT * FROM users;

Здесь SQL-выражение начинается с команды SELECT, которая позволяет извлекать данные из БД.

За командой SELECT идёт символ звёздочки (*). Тут он олицетворяет все столбцы таблицы. Это значит, что мы хотим извлечь данные из всех столбцов.

Если вы хоть немного понимаете английский, то ключевое слово FROM в дополнительных пояснениях не нуждается.

И, наконец, users — это имя таблицы, из которой мы хотим извлечь данные.

Если «перевести» вышеприведённое SQL-выражение на обычный язык, то получится следующее:

Получить данные всех столбцов из таблицы users.

Давайте теперь сделаем вышеописанное SQL-выражение немного интереснее:

SELECT * FROM users WHERE user=’Fyodor’;

В данном случае мы указываем на то, что хотим получить лишь запись, в поле user которой имеется имя пользователя Fyodor. Все остальные записи таблицы нас не интересуют.

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

▍Команды и ключевые слова SQL


Теперь, в завершение этого раздела, хочу рассказать о некоторых наиболее часто используемых командах и ключевых словах SQL. Для того чтобы понять то, о чём речь пойдёт дальше, знать все эти команды и ключевые слова вам необязательно, но я настоятельно рекомендую вам поближе с ними познакомиться после того, как вы дочитаете эту статью.

  • SELECT: получение данных из таблицы.
  • INSERT INTO: добавление записи в таблицу.
  • UPDATE: обновление содержимого записи таблицы.
  • DELETE: удаление записи из таблицы.
  • CREATE TABLE: создание новой таблицы.
  • WHERE: фильтрация записей по заданному условию.
  • ORDER BY: сортировка данных, полученных с помощью SELECT.

Теперь, разобрав основы, переходим к нашей основной теме.

SQL-инъекции


Как уже было сказано, SQL-инъекции — это разновидность атаки на веб-приложения. В ходе проведения такой атаки делается попытка модификация SQL-выражения, которое приложение отправляет базе данных. Выполняется атака путём подстановки особым образом подготовленных данных в поля ввода, которые может заполнять пользователь.

Для того чтобы вышесказанное стало бы понятнее — рассмотрим пример.

▍Простая атака с использованием SQL-инъекции


Предположим, имеется форма аутентификации, которая предлагает пользователю ввести в её поля имя и пароль. Приложение предоставляет пользователям доступ к закрытым ресурсам после проверки введённых данных. Если говорить точнее, то приложение отправляет к базе данных SQL-запрос, направленный на проверку наличия там тех данных, которые ввёл пользователь. Используемое при этом SQL-выражение может выглядеть примерно так:

SELECT * FROM users WHERE username=’ProvidedUsername’ and password=’ProvidedPassword’;

Если вы внимательно читали статью, то вы без труда поймёте эту конструкцию. Она извлекает из таблицы users все записи, фильтруя их по имени пользователя (поле username) ProvidedUsername и по паролю (password) ProvidedPassword. Если в таблице имеется запись, удовлетворяющая этим двум условиям — это значит, что пользователь ввёл верные имя и пароль. Приложение, в результате, даст такому пользователю доступ к закрытым ресурсам.

Теперь представьте, что вместо того, чтобы ввести в поле формы имя, пользователь вводит туда следующее:

a’ OR 1=1;--

А затем, в качестве пароля, вводит произвольный набор символов (то, что будет введено в поле для пароля, значения не имеет; ниже мы с этим разберёмся).

После этого приложение формирует такое SQL-выражение:

SELECT * FROM users WHERE username=’a’ OR 1=1;--’ and password=’RandomPass’;

База данных, обрабатывая такой запрос, вернёт любую запись из таблицы users, в поле username которой находится a. Запись будет возвращена и в том случае, если истинным является выражение 1=1.

Но выражение 1=1 всегда истинно, поэтому этот запрос приведёт к получению всех записей из таблицы.

Кроме того, так как два дефиса в SQL используются для оформления однострочных комментариев, всё, что идёт после них, окажется закомментированным, то есть — соответствующие команды базой данных обрабатываться не будут. Если выделить ту часть SQL-запроса, которая будет выполнена базой данных, то получится следующее:

SELECT * FROM users WHERE username=’a’ OR 1=1;--’ and password=’RandomPass’;

База данных, обрабатывая этот запрос, вернёт список записей, не являющихся NULL-значениями, и, в результате, веб-приложение даст пользователю доступ к закрытым ресурсам.

Итоги


Мы рассмотрели лишь один пример SQL-инъекции. Но существует и множество других способов внедрения SQL-кода в веб-приложения. Если вы хотите посмотреть больше примеров — рекомендую взглянуть на этот материал, опубликованный на сайте Netsparker, и на этот материал с сайта PortSwigger.

Если вы хотите попрактиковаться в деле выполнения атак на веб-приложения с использованием SQL-инъекций — попытайте удачу в варгейме Natas на OverTheWire. Если вы не знаете о том, что это такое — вот моя статья об этом.

Как вы защищаете свои веб-проекты от SQL-инъекций?

RUVDS.com
VDS/VPS-хостинг. Скидка 10% по коду HABR

Комментарии 21

    +7

    Хоть бы намекнули про prepared statements, они же подготовленные выражения или связываемые переменные.

      +2

      База данных, обрабатывая этот запрос, вернёт список записей, не являющихся NULL-значениями


      Нет. Она вернет все записи из-за OR 1=1, так как NULL OR TRUE = TRUE

        +4

        Сколько можно мусолить уже эти sql инъекции? 1000 статей про них написаны, и про методы противодействия тоже.

          +3
          По-видимому, 17 человек не просто пользуются голым SQL, но ещё и собирают его из входных параметров. В 2021 году.
            0
            А что не так с голым SQL? ORM имеет гораздо меньше возможностей и мешает создать именно ту структуру, которую хочет разработчик (для сложных запросов без ручного составления все равно не обойтись, а структура уже не та).
              +1

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

                0
                Тогда согласен, смутила первая часть фразы оратора выше.
          +2

          А зачем знакомиться, если эту проблему решили мульён лет назад?
          Кодеров работающих по принципу копи/паст из первого попавшегося текста времен мамонтов не считаем.

            0
            Это не мешает появляться новому коду с этими проблемами в проде. Уж лучше лишний раз напомнить.
              0

              Или поменять програмистов/HR/QR/WHATEVER.
              Ну это просто дичь из строк собирать SQL запрос, не ?

                0
                Конечно, дичь.
                «Можно нанять более адекватного программиста, но это ведь дороже. За эти деньги лучше взять двух студентов и ещё на пиво останется» — говорит один пузатый дядя, которому надо отчитываться о бюджете, так как его бонус зависит только от этого фактора.
                  +1

                  И для кого статья? Для пузатого дяди или студента который ее не прочитает (надо срочно и вчера)?
                  А если по полной утрировать ?


                  После того как "дым рассеется" студент найдет кучу статей

                    0
                    Статья для студента. Дяде уже ничего не поможет (хотя, есть варианты, но такая глубокая анатомия обычно выходит за рамки Хабра-тематики).
                    Студент найдёт только если будет знать что это надо искать. На Хабре статьи обычно не ищут, а просто читают ленту.
                      0

                      Если "нужно вчера" (других причин не вижу делать на отъе....) то студент будет искать "как сконкатенировать 2 выражения в SQL строку" извините.
                      И пропустит эти ваши непонятные инъекции )

                        0
                        Для соединения строк не надо добавлять ключевое слово «SQL».
                          0

                          А где об этом сказано?
                          Вот о том и речь, что непонятно что ищете.

                            0

                            Это надо говорить не нам, это надо говорить студентам. Которые на тостер пишут вопросы вида "у меня база данных все переводы строк съела".


                            Да и преподавателям тоже, у которых например sprintf — это функция для составления SQL запросов.

                              0
                              Верно. Вот как раз для них эта статья.
              0
              Отцы-основатели еще в дремучие годы предусмотрели все это. И не только Static, но и Embedded SQL.
                +1
                Если пишете «в общем», то старайтесь приводить примеры, которые будут работать на максимальном количестве СУБД. Ну или хотя бы на самых популярных. Чтобы любопытный, но неопытный пользователь мог воспроизвести написанное.

                Например, в достаточно популярной MySQL запрос с инъекцией сам по себе выполнен, конечно, будет, но вот при выполнении из программы на ЯВУ обратно прилетит ошибка
                You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '--' and password='RandomPass'' at line 1
                А всё потому, что с точки зрения MySQL '--' является комментарием лишь когда после него поставлен пробел.
                  0

                  Не просто низкий, а очень низкий технический уровень материала.


                  Тут как раз на днях была статья про то как за маркетингом не видно человека.
                  Вот здесь как раз этот самый случай: помимо бюджета на продвижение компании в интернете есть вообще-то ещё и читатель, для которого, по крайней мере в теории, пишутся статьи на хабре. А этот читатель не вынесет из данной статьи вообще ничего.

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

                  Самое читаемое