TL; DR
-- The application accepts input, in this case 'Nancy', without attempting to
-- sanitize the input, such as by escaping special characters
school=> INSERT INTO students VALUES ('Nancy');
INSERT 0 1
-- SQL injection occurs when input into a database command is manipulated to
-- cause the database server to execute arbitrary SQL
school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
INSERT 0 1
DROP TABLE
-- The student records are now gone - it could have been even worse!
school=> SELECT * FROM students;
ERROR: relation "students" does not exist
LINE 1: SELECT * FROM students;
^
Это удаляет (удаляет) таблицу ученика.
( Все примеры кода в этом ответе выполнялись на сервере базы данных PostgreSQL 9.1.2. )
Чтобы прояснить, что происходит, давайте попробуем это с простой таблицей, содержащей только поле имени, и добавим одну строку:
school=> CREATE TABLE students (name TEXT PRIMARY KEY);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "students_pkey" for table "students"
CREATE TABLE
school=> INSERT INTO students VALUES ('John');
INSERT 0 1
Предположим, что приложение использует следующий SQL для вставки данных в таблицу:
INSERT INTO students VALUES ('foobar');
Заменить foobar
фактическим именем ученика. Обычная операция вставки будет выглядеть так:
-- Input: Nancy
school=> INSERT INTO students VALUES ('Nancy');
INSERT 0 1
Когда мы запрашиваем таблицу, мы получаем это:
school=> SELECT * FROM students;
name
-------
John
Nancy
(2 rows)
Что происходит, когда мы вставляем в таблицу имя Бобби Беблс?
-- Input: Robert'); DROP TABLE students; --
school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
INSERT 0 1
DROP TABLE
Внедрение SQL здесь является результатом того, что имя студента завершает утверждение и включает отдельную команду DROP TABLE
; две черты в конце ввода предназначены для закомментирования любого оставшегося кода, который в противном случае мог бы вызвать ошибку. Последняя строка вывода подтверждает, что сервер базы данных отбросил таблицу.
Важно отметить, что во время операции INSERT
приложение не проверяет ввод на наличие каких-либо специальных символов и поэтому разрешает вводить произвольный ввод в команду SQL. Это означает, что злонамеренный пользователь может вставить в поле, обычно предназначенное для ввода пользователя, специальные символы, такие как кавычки, а также произвольный код SQL, чтобы заставить систему базы данных выполнить его, следовательно, SQL инъекция .
Результат?
school=> SELECT * FROM students;
ERROR: relation "students" does not exist
LINE 1: SELECT * FROM students;
^
SQL-инъекция - это эквивалент базы данных удаленного выполнения произвольного кода уязвимость в операционной системе или приложении. Потенциальное влияние успешной атаки SQL-инъекцией нельзя недооценивать - в зависимости от системы базы данных и конфигурации приложения злоумышленник может использовать ее для потери данных (как в этом случае), получения несанкционированного доступа к данным или даже выполнения произвольный код на самом хосте.
Как отмечалось в комиксе XKCD, один из способов защиты от атак с использованием SQL-инъекций состоит в том, чтобы санировать входные данные базы данных, например, экранируя специальные символы, чтобы они не могли изменить основную команду SQL и, следовательно, не могли вызвать выполнение произвольного кода SQL. Если вы используете параметризованные запросы, такие как SqlParameter
в ADO.NET, входные данные, как минимум, будут автоматически очищены для защиты от внедрения SQL.
Однако очистка входных данных на уровне приложений может не остановить более продвинутые методы внедрения SQL. Например, есть способы обойти функцию mysql_real_escape_string
PHP . Для дополнительной защиты многие системы баз данных поддерживают подготовленные операторы . При правильной реализации в бэкэнде подготовленные операторы могут сделать внедрение SQL невозможным, обработав ввод данных как семантически отдельный от остальной части команды.