Как работает SQL-инъекция из комикса XKCD «Таблицы Бобби»?

Просто смотрю на:

XKCD Strip (Источник: https://xkcd.com/327/ )

Что делает этот SQL:

Robert'); DROP TABLE STUDENTS; --

Я знаю и то, 'и другое --для комментариев, но разве это слово тоже не DROPкомментируется, поскольку оно является частью одной строки?

1.12.2008 21:50:10
Если вы слушаете подкаст Stack Overflow № 31 (27 ноября 2008 г.), они на самом деле обсуждают это.
EBGreen 1.12.2008 21:57:35
В MySQL 'нет комментариев . Даже если бы это было, перед ним нет пробела, поэтому он может заканчивать только строку, предшествующую ему.
Lightness Races in Orbit 1.09.2011 12:14:12
Что касается XKCD, если есть какие-либо вопросы по поводу некоторых комиксов, вы всегда можете перейти к объяснению XKCD и выяснить свой ответ. Существует даже вики XKCD , которая очень полезна для некоторых хитрых комиксов, таких как геохэшинг XKCD
Anatoli 14.09.2011 19:56:24
Я считаю, что эта ссылка должна быть записана здесь: bobby-tables.com
Arioch 'The 1.11.2012 05:54:41
beta.companieshouse.gov.uk/company/10542519 - это регистрация для консультанта с именем; DROP TABLE "КОМПАНИИ"; - ООО
Alex Dupuy 4.01.2017 21:03:12
13 ОТВЕТОВ
РЕШЕНИЕ

Это опускает стол студентов.

Оригинальный код в школьной программе, вероятно, выглядит примерно так

q = "INSERT INTO Students VALUES ('" + FNMName.Text + "', '" + LName.Text + "')";

Это наивный способ добавить ввод текста в запрос, и , как вы увидите , он очень плохой .

После того, как значения из первого имени, текстового поля второго имени FNMName.Text (которое есть Robert'); DROP TABLE STUDENTS; --) и текстового поля фамилии LName.Text (давайте назовем его Derper) будут объединены с остальной частью запроса, результатом теперь фактически являются два запроса, разделенных терминатор (точка с запятой). Второй запрос был введен в первый. Когда код выполняет этот запрос к базе данных, он будет выглядеть так

INSERT INTO Students VALUES ('Robert'); DROP TABLE Students; --', 'Derper')

что на простом английском языке примерно переводит на два запроса:

Добавьте новую запись в таблицу учеников со значением имени «Роберт»

а также

Удалить таблицу студентов

Все после второго запроса помечается как комментарий : --', 'Derper')

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

Отредактировано снова в соответствии с проницательным комментарием dan04

1112
23.05.2017 12:02:58
Ммм, WHERE с круглыми скобками вокруг аргументов довольно необычен, но, по крайней мере, избегает синтаксической ошибки ... :-)
PhiLho 2.12.2008 20:00:15
@PhiLho: Если бы оригинальное утверждение было INSERT, тогда скобки имели бы больше смысла. Это также объясняет, почему соединение с базой данных не находится в режиме только для чтения.
dan04 10.08.2010 04:02:45
Как объясняет @ dan04, скобки имеют больше смысла с INSERT. Думая об обратном, SELECTони все равно не будут работать, так как вставка маленьких таблиц Бобби в стол уже бы опустила стол.
ypercubeᵀᴹ 21.01.2013 21:41:12
На самом деле, в этом примере первый запрос («добавить новую запись ...») потерпит неудачу, так как Studentsожидает больше, чем один столбец (исходный / правильный оператор содержит два столбца). Тем не менее, наличие второго столбца полезно, чтобы показать, почему комментирование требуется; и поскольку никто не может изменить имя Бобби, вероятно, лучше оставить его как есть с небольшим, чем это наблюдение, в качестве сноски.
eggyal 27.04.2013 23:38:57
Фамилия Бобби - или, по крайней мере, его матери, Робертс , согласно Объяснению XKCD . Я не уверен, что исправление, которое улучшило бы ясность ответа, все же.
WBT 3.08.2016 18:29:49

На ');торцах запроса, он не начинает комментарий. Затем он удаляет таблицу студентов и комментирует оставшуюся часть запроса, который должен был быть выполнен.

18
12.04.2010 08:18:28

Символ 'в SQL используется для строковых констант. В этом случае он используется для окончания строковой константы, а не для комментария.

16
12.04.2010 08:17:38

Автор базы данных, вероятно, сделал

sql = "SELECT * FROM STUDENTS WHERE (STUDENT_NAME = '" + student_name + "') AND other stuff";
execute(sql);

Если имя студента указано, это делает выбор с именем «Роберт», а затем отбрасывает таблицу. Часть «-» изменяет оставшуюся часть данного запроса в комментарий.

17
1.12.2008 22:46:58
Это была моя первая мысль, но вы получили синтаксическую ошибку с завершающими закрывающими скобками, нет?
PhiLho 1.12.2008 22:03:18
Вот почему в конце есть знак, указывающий, что оставшийся текст является комментарием и должен игнорироваться.
user1228 1.12.2008 22:08:40

Допустим, имя использовалось в переменной $Name.

Затем вы запускаете этот запрос :

INSERT INTO Students VALUES ( '$Name' )

Код ошибочно помещает все, что пользователь указал в качестве переменной.

Вы хотели, чтобы SQL был:

ВСТАВЬТЕ В СТОИМОСТЬ СТУДЕНТОВ (' Robert Tables`)

Но умный пользователь может предоставить все, что он хочет:

ВСТАВЬТЕ В СТОИМОСТЬ СТУДЕНТОВ (' Robert'); DROP TABLE Students; --')

Что вы получаете:

INSERT INTO Students VALUES ( 'Robert' );  DROP TABLE STUDENTS; --' )

--Только комментарии остаток строки.

609
19.04.2020 11:53:39
Это намного лучше, чем голосование за наибольшее количество голосов, потому что оно объясняет закрывающую скобку.
Tim Büthe 13.08.2010 12:39:01
Кстати, школьный директор в комиксах не может знать об этом или XSS, поскольку таблица учеников удалена, он не может знать, кто это сделал.
xryl669 28.02.2020 15:00:17
@ xryl669 Журналы очень полезны в подобных ситуациях ... Иногда все запросы записываются в журнал, а иногда другая информация в журнале может помочь вам определить виновника.
inemanja 5.03.2020 20:25:25

В этом случае 'не является символом комментария. Он используется для разделения строковых литералов. Художник комиксов полагается на идею, что у рассматриваемой школы есть динамический sql, который выглядит примерно так:

$sql = "INSERT INTO `Students` (FirstName, LastName) VALUES ('" . $fname . "', '" . $lname . "')";

Так что теперь символ 'завершает строковый литерал до того, как программист ожидал этого. В сочетании с; Чтобы завершить оператор, теперь злоумышленник может добавить любой SQL-запрос. Комментарий в конце должен убедиться, что любой оставшийся sql в исходном операторе не препятствует компиляции запроса на сервере.

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

17
11.12.2014 15:24:44

Скажем, вы наивно написали метод создания ученика следующим образом:

void createStudent(String name) {
    database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
}

И кто-то вводит имя Robert'); DROP TABLE STUDENTS; --

Что запускается в базе данных, это запрос:

INSERT INTO students (name) VALUES ('Robert'); DROP TABLE STUDENTS --')

Точка с запятой завершает команду вставки и запускает другую; - комментирует остальную часть строки. Команда DROP TABLE выполнена ...

Вот почему параметры связывания - это хорошо.

30
1.12.2008 21:56:45

Нет, 'это не комментарий в SQL, а разделитель.

Мама предположила, что программист базы данных сделал запрос, похожий на:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('$firstName', '$lastName');

(например), чтобы добавить нового студента, где $xxxсодержимое переменной было взято непосредственно из HTML-формы, без проверки формата и экранирования специальных символов.

Таким образом, если база данных $firstNameсодержит Robert'); DROP TABLE students; --программу, она выполнит следующий запрос непосредственно в БД:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('Robert'); DROP TABLE students; --', 'XKCD');

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

Ммм, я слишком медленный, я вижу уже 8 ответов перед моим в оранжевой полосе ... :-) Кажется, популярная тема.

71
22.07.2014 18:34:30

Одиночная кавычка - это начало и конец строки. Точка с запятой - это конец утверждения. Так что, если они делают выбор, как это:

Select *
From Students
Where (Name = '<NameGetsInsertedHere>')

SQL станет:

Select *
From Students
Where (Name = 'Robert'); DROP TABLE STUDENTS; --')
--             ^-------------------------------^

В некоторых системах selectсначала запускается команда с последующим dropоператором! Сообщение: не вставляйте значения в ваш SQL. Вместо этого используйте параметры!

26
15.09.2011 06:39:16

Как уже отмечали все остальные, ');первоначальное утверждение закрывается, а затем следует второе. Большинство фреймворков, в том числе такие языки, как PHP, к настоящему времени имеют настройки безопасности по умолчанию, которые не позволяют использовать несколько операторов в одной строке SQL. Например, в PHP вы можете использовать несколько операторов только в одной строке SQL, используя mysqli_multi_queryфункцию.

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

$query="SELECT * FROM users WHERE username='" . $_REQUEST['user'] . "' and (password='".$_REQUEST['pass']."')";
$result=mysql_query($query);

Если вы укажете peterимя пользователя и secretпароль, результирующая строка SQL будет выглядеть так:

SELECT * FROM users WHERE username='peter' and (password='secret')

Все в порядке. Теперь представьте, что вы предоставляете эту строку в качестве пароля:

' OR '1'='1

Тогда результирующая строка SQL будет такой:

SELECT * FROM users WHERE username='peter' and (password='' OR '1'='1')

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

164
20.02.2013 08:42:21

TL; DR

- Приложение принимает входные данные, в данном случае «Нэнси», не пытаясь санировать входные данные, например, избегая специальных символов 
school => INSERT INTO студентов VALUES ( «Нэнси» ); ВСТАВИТЬ 0 1
   
  

- инъекции SQL происходит , когда вход в команду базы данных манипулируют , чтобы - вызвать сервер базы данных выполнить произвольный SQL 
школы => INSERT INTO студентов VALUES ( «Robert» ); DROP TABLE студенты ; - '); INSERT 0 1 DROP TABLE
      
  
 

- Студенческие записи сейчас ушли - могло быть и хуже! 
школа => ВЫБРАТЬ * ОТ студентов ; 
ОШИБКА :   соотношению «студенты» вовсе не существует   
ЛИНИЯ 1 : ВЫБРАТЬ * ОТ СТУДЕНТОВ ; ^   
                      

Это удаляет (удаляет) таблицу ученика.

( Все примеры кода в этом ответе выполнялись на сервере базы данных PostgreSQL 9.1.2. )

Чтобы было понятно, что происходит, давайте попробуем это с простой таблицей, содержащей только поле имени, и добавим одну строку:

школа => CREATE TABLE студентов ( название TEXT PRIMARY KEY ); 
ВНИМАНИЕ : CREATE TABLE / PRIMARY KEY будет создавать неявную индекс "students_pkey" для таблицы "Студенты" CREATE TABLE 
школы => INSERT INTO студентов ЗНАЧЕНИЯ ( 'Джон' ); ВСТАВИТЬ 0 1             
    
  

Предположим, что приложение использует следующий SQL для вставки данных в таблицу:

INSERT INTO студентов ЗНАЧЕНИЯ ( 'Foobar' );  

Заменить foobarна настоящее имя студента. Обычная операция вставки будет выглядеть так:

- Вход: Nancy 
школа => INSERT INTO студентов ЗНАЧЕНИЯ ( 'Нэнси' ); ВСТАВИТЬ 0 1   
  

Когда мы запрашиваем таблицу, мы получаем это:

школа => ВЫБРАТЬ * ОТ студентов ;   
 имя
-------
 Джон
 Нэнси
( 2 ряда ) 

Что происходит, когда мы вставляем имя Little Bobby Tables в таблицу?

- вход: Роберт '); DROP TABLE студенты; - 
школа => INSERT INTO студентов ЗНАЧЕНИЯ ( 'Роберт' ); DROP TABLE студенты ; - '); INSERT 0 1 DROP TABLE      
  
 

Внедрение SQL здесь является результатом того, что имя студента завершает оператор и включает отдельную DROP TABLEкоманду; две черты в конце ввода предназначены для закомментирования любого оставшегося кода, который в противном случае мог бы вызвать ошибку. Последняя строка вывода подтверждает, что сервер базы данных отбросил таблицу.

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

Результат?

школа => ВЫБРАТЬ * ОТ студентов ; 
ОШИБКА :   соотношению «студенты» вовсе не существует   
ЛИНИЯ 1 : ВЫБРАТЬ * ОТ СТУДЕНТОВ ; ^   
                      

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

Как отмечалось в комиксе XKCD, одним из способов защиты от атак с использованием SQL-инъекций является очистка входных данных базы данных, например, путем экранирования специальных символов, чтобы они не могли изменить основную команду SQL и, следовательно, не могли вызвать выполнение произвольного кода SQL. Если вы используете параметризованные запросы, такие как использование SqlParameterв ADO.NET, входные данные, как минимум, будут автоматически очищены для защиты от внедрения SQL.

Однако очистка входных данных на уровне приложений может не остановить более продвинутые методы внедрения SQL. Например, есть способы обойти mysql_real_escape_stringфункцию PHP . Для дополнительной защиты многие системы баз данных поддерживают подготовленные операторы . При правильной реализации в бэкэнде подготовленные операторы могут сделать внедрение SQL невозможным, обрабатывая ввод данных как семантически отдельный от остальной части команды.

39
11.06.2018 03:16:49

Вот как это работает: предположим, что администратор ищет записи ученика

Robert'); DROP TABLE STUDENTS; --

Поскольку учетная запись администратора имеет высокие привилегии, удаление таблицы из этой учетной записи возможно.

Код для получения имени пользователя из запроса

Теперь запрос будет выглядеть примерно так (для поиска в таблице учеников)

String query="Select * from student where username='"+student_name+"'";

statement.executeQuery(query); //Rest of the code follows

Результирующий запрос становится

Select * from student where username='Robert'); DROP TABLE STUDENTS; --

Поскольку пользовательский ввод не очищен, приведенный выше запрос состоит из 2 частей

Select * from student where username='Robert'); 

DROP TABLE STUDENTS; --

Двойная черта (-) просто закомментирует оставшуюся часть запроса.

Это опасно, так как может аннулировать аутентификацию по паролю, если она присутствует

Первый сделает нормальный поиск.

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

7
11.07.2016 16:56:24
SELECT* FROM sutdents ...- вы забыли "с". Это то, что вы бросаете. DROP TABLE STUDENTS;
DevWL 30.07.2019 22:43:10

Вам не нужно вводить данные формы, чтобы сделать SQL-инъекцию.

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

В основном мы будем пытаться исправить патч ввода. Но это не единственное место, где можно атаковать с помощью SQL-инъекции. Вы можете сделать очень простую атаку с URL, который отправляет данные через запрос GET; Рассмотрим следующий пример:

<a href="/show?id=1">show something</a>

Ваш URL будет выглядеть http://yoursite.com/show?id=1

Теперь кто-то может попробовать что-то вроде этого

http://yoursite.com/show?id=1;TRUNCATE table_name

Попробуйте заменить table_name реальным именем таблицы. Если он получит правильное название вашей таблицы, они очистят вашу таблицу! (Очень просто взломать этот URL простым скриптом)

Ваш запрос будет выглядеть примерно так ...

"SELECT * FROM page WHERE id = 4;TRUNCATE page"

Пример уязвимого кода PHP с использованием PDO:

<?php
...
$id = $_GET['id'];

$pdo = new PDO($database_dsn, $database_user, $database_pass);
$query = "SELECT * FROM page WHERE id = {$id}";
$stmt = $pdo->query($query);
$data = $stmt->fetch(); 
/************* You have lost your data!!! :( *************/
...

Решение - используйте методы PDO prepare () и bindParam ():

<?php
...
$id = $_GET['id'];

$query = 'SELECT * FROM page WHERE id = :idVal';
$stmt = $pdo->prepare($query);
$stmt->bindParam('idVal', $id, PDO::PARAM_INT);
$stmt->execute();
$data = $stmt->fetch();
/************* Your data is safe! :) *************/
...
4
7.08.2019 22:20:19