Jak działa SQL injection z komiksu" Bobby Tables " XKCD?

Właśnie patrzę:

Taśma XKCD(Źródło: https://xkcd.com/327/)

Do czego służy ten SQL:

Robert'); DROP TABLE STUDENTS; --

Wiem, że zarówno ' jak i {[2] } są dla komentarzy, ale czy słowo DROP nie jest komentowane, ponieważ jest częścią tej samej linii?

Author: Floern, 2008-12-02

12 answers

Upuszcza uczniom stół.

Oryginalny kod w programie szkoły prawdopodobnie wygląda jak

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

Jest to naiwny sposób dodawania tekstu do zapytania i jest bardzo zły, jak zobaczysz.

Po wartościach od imienia, pole tekstowe middle name FNMName.Tekst (który jest Robert'); DROP TABLE STUDENTS; --) i pole tekstowe nazwisko LName.Tekst (nazwijmy go Derper) jest konkatenowany z resztą zapytania, wynik jest teraz w rzeczywistości dwa zapytania oddzielone terminatorem instrukcji (średnik). Drugie zapytanie zostało wstrzyknięte do pierwszego. Gdy kod wykona to zapytanie względem bazy danych, będzie wyglądało tak:

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

Co w prostym języku angielskim tłumaczy się z grubsza na dwa zapytania:

Dodaj nowy rekord do tabeli uczniów z wartością imienia 'Robert'

I

Usuń uczniów tabela

Wszystko po drugim zapytaniu jest oznaczone jako komentarz: --', 'Derper')

' w imieniu ucznia nie jest komentarzem, tylko zamykającym ogranicznikiem ciągu. Ponieważ imię ucznia jest ciągiem znaków, jest ono potrzebne składniowo do wypełnienia hipotetycznego zapytania. Ataki Injection działają tylko , gdy zapytanie SQL, które wstrzykują, daje poprawny SQL.

edytowane again Jak na dan04 's astute komentarz

 1032
Author: Will,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:58

Załóżmy, że nazwa została użyta w zmiennej $Name. Następnie uruchom to zapytanie:

INSERT INTO Students VALUES ( '$Name' )

Kod błędnie umieszcza wszystko, co użytkownik podał jako zmienną. Chciałeś, aby SQL był:

INSERT INTO uczniowie VALUES ("Robert Tables` )

Ale sprytny użytkownik może dostarczyć co chce:

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

What you get jest:

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

-- komentuje tylko resztę wiersza.

 558
Author: sinoth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-24 13:45:43

Jak wszyscy już zauważyli, '); zamyka oryginalną instrukcję, a następnie następuje druga Instrukcja. Większość frameworków, w tym języków takich jak PHP, ma teraz domyślne ustawienia zabezpieczeń, które nie zezwalają na wiele wyrażeń w jednym ciągu SQL. Na przykład w PHP można uruchamiać tylko kilka instrukcji w jednym łańcuchu SQL za pomocą funkcji mysqli_multi_query.

Można jednak manipulować istniejącą instrukcją SQL za pomocą SQL injection bez konieczności dodawania drugiej instrukcji. Załóżmy, że masz system logowania, który sprawdza nazwę użytkownika i hasło za pomocą tego prostego select:

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

Jeśli podasz peter jako nazwę użytkownika i secret jako hasło, wynikowy ciąg SQL będzie wyglądał następująco:

SELECT * FROM users WHERE username='peter' and (password='secret')
Wszystko w porządku. Teraz wyobraź sobie, że podajesz ten ciąg jako hasło:
' OR '1'='1

Wtedy wynikowy ciąg SQL będzie następujący:

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

To umożliwi Ci zalogowanie się na dowolne konto bez znajomości hasła. Więc nie musisz być w stanie użyć dwóch instrukcji w celu użycia SQL injection, chociaż możesz zrobić bardziej destrukcyjne rzeczy, jeśli jesteś w stanie dostarczyć wiele instrukcji.

 146
Author: Johannes Fahrenkrug,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-20 08:42:21

Nie, ' nie jest komentarzem w SQL, ale ogranicznikiem.

Mama przypuszczała, że programista baz danych złożył prośbę wyglądającą następująco:

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

(na przykład), aby dodać nowego ucznia, gdzie zawartość zmiennej $xxx została pobrana bezpośrednio z formularza HTML, bez sprawdzania formatu ani znaków specjalnych.

Więc jeśli $firstName zawiera Robert'); DROP TABLE students; -- program bazy danych wykona następujące żądanie bezpośrednio na DB:

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

Ie. to zakończy się wcześniej insert oświadczenie, wykonaj dowolny złośliwy kod, który chce cracker, a następnie skomentuj resztę kodu, który może być.

Mmm, jestem za wolny, widzę już 8 odpowiedzi przed moimi w pomarańczowym paśmie... :- ) Popularny temat, jak się wydaje.

 69
Author: PhiLho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-22 18:34:30

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;
                      ^

To usuwa (usuwa) stół ucznia.

(wszystkie przykłady kodu w tej odpowiedzi zostały uruchomione na serwerze bazy danych PostgreSQL 9.1.2.)

Aby wyjaśnić, co się dzieje, spróbujmy użyć prostej tabeli zawierającej tylko pole nazwa i dodać pojedynczy wiersz:

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

Załóżmy, że aplikacja używa następującego SQL do wstawiania danych do tabeli:

INSERT INTO students VALUES ('foobar');

Zastąp foobar rzeczywistym imieniem i nazwiskiem ucznia. Normalna operacja insert wyglądałaby tak:

--                            Input:   Nancy
school=> INSERT INTO students VALUES ('Nancy');
INSERT 0 1

Gdy zapytamy tabelę, otrzymujemy to:

school=> SELECT * FROM students;
 name
-------
 John
 Nancy
(2 rows)

Co się stanie, gdy wstawimy Imię małego Bobby ' ego do stołu?

--                            Input:   Robert'); DROP TABLE students; --
school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
INSERT 0 1
DROP TABLE

SQL injection jest wynikiem nazwy ucznia kończącego instrukcję i zawierającego osobne polecenie DROP TABLE; dwa myślniki na końcu wejścia mają na celu skomentowanie dowolnego pozostałego kodu, który w przeciwnym razie spowodowałby błąd. Ostatnia linia wyjścia potwierdza, że serwer bazy danych upuścił tabelę.

Ważne jest, aby zauważyć, że podczas operacji INSERT aplikacja nie sprawdza danych wejściowych pod kątem znaków specjalnych i w związku z tym umożliwia dowolne wprowadzanie danych wejściowych do polecenia SQL. Oznacza to, że złośliwy użytkownik może wstawić do pola Zwykle przeznaczonego do wprowadzania przez użytkownika specjalne symbole, takie jak cudzysłowy wraz z dowolnym kodem SQL, aby system bazy danych mógł je wykonać, a zatem SQL injection.

Wynik?

school=> SELECT * FROM students;
ERROR:  relation "students" does not exist
LINE 1: SELECT * FROM students;
                      ^
SQL injection jest bazodanowym odpowiednikiem zdalnego arbitralnego wykonywania kodu w systemie operacyjnym lub aplikacji. W zależności od konfiguracji systemu bazy danych i aplikacji atakujący może go wykorzystać do spowodowania utraty danych( jak w tym przypadku), uzyskania nieautoryzowanego dostępu do danych lub nawet wykonania dowolny kod na samej maszynie hosta.

Jak zauważył komiks XKCD, jednym ze sposobów ochrony przed atakami SQL injection jest dezaktywacja danych wejściowych, na przykład poprzez unikanie znaków specjalnych, tak aby nie mogły one zmodyfikować bazowego polecenia SQL, a tym samym nie mogły spowodować wykonania dowolnego kodu SQL. Jeśli korzystasz z zapytań parametryzowanych, np. za pomocą SqlParameter w ADO.NET, dane wejściowe będą co najmniej automatycznie dezynfekowane w celu ochrony przed SQL wstrzyknięcie.

Jednak dezynfekcja danych wejściowych na poziomie aplikacji może nie zatrzymać bardziej zaawansowanych technik SQL injection. Na przykład, istnieją sposoby obejścia mysql_real_escape_string funkcji PHP. Dla Dodatkowej Ochrony, wiele systemów bazodanowych obsługuje przygotowane Oświadczenia. Jeśli poprawnie zaimplementowane w backendzie, przygotowane instrukcje mogą uniemożliwić SQL injection, traktując dane wejściowe jako semantycznie oddzielone od reszty polecenia.

 34
Author: bwDraco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-11 03:16:49

Powiedzmy, że naiwnie napisałeś taką metodę tworzenia ucznia:

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

I ktoś wpisuje nazwę Robert'); DROP TABLE STUDENTS; --

To, co zostanie uruchomione w bazie danych, to zapytanie:

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

Średnik kończy polecenie insert i rozpoczyna kolejne; -- komentuje resztę wiersza. Wykonywana jest komenda DROP TABLE...

Dlatego parametry bind są dobrą rzeczą.

 27
Author: Dan Vinton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-01 21:56:45

Pojedynczy cudzysłów jest początkiem i końcem łańcucha znaków. Średnik jest końcem instrukcji. Więc gdyby robili taki select:

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

SQL stałby się:

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

W niektórych systemach, select zostanie uruchomiony jako pierwszy, a następnie drop oświadczenie! Komunikat brzmi: nie osadzaj wartości w SQL. Zamiast tego użyj parametrów!

 24
Author: CodeAndCats,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-15 06:39:16

'); kończy zapytanie, nie uruchamia komentarza. Następnie opuszcza tabelę uczniów i komentuje resztę zapytania, które miało zostać wykonane.

 16
Author: Jorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-12 08:18:28

Autor bazy danych prawdopodobnie zrobił

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

Jeśli podana jest nazwa student_name, zaznacza się ją imieniem "Robert", a następnie opuszcza tabelę. Część " -- " zmienia resztę podanego zapytania w komentarz.

 15
Author: Paul Tomblin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-01 22:46:58

W tym przypadku ' nie jest znakiem komentarza. Służy do rozgraniczania liter ciągów. Komiks opiera się na pomyśle, że dana szkoła ma gdzieś dynamiczny sql, który wygląda mniej więcej tak:

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

Tak więc teraz znak ' kończy łańcuch znaków, zanim programista się tego spodziewał. W połączeniu ze znakiem;, aby zakończyć instrukcję, atakujący może teraz dodać dowolny sql, który chce. -- Comment na końcu ma na celu upewnienie się, że pozostały sql w oryginalna instrukcja nie uniemożliwia kompilacji zapytania na serwerze.

FWIW, też uważam, że dany komiks ma zły szczegół: jeśli myślisz o dezynfekcji danych wejściowych do bazy danych, jak sugeruje komiks, nadal robisz to źle. Zamiast tego powinieneś myśleć w kategoriach kwarantanny danych wejściowych, a prawidłowym sposobem na to jest parametryzowanie zapytań.

 15
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-11 15:24:44

Znak ' W SQL jest używany do stałych łańcuchów. W tym przypadku służy do kończenia stałej łańcuchowej, a nie do komentowania.

 14
Author: Rockcoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-12 08:17:38

Tak to działa: Załóżmy, że administrator szuka rekordów studenta

Robert'); DROP TABLE STUDENTS; --

Ponieważ konto administratora ma wysokie uprawnienia, możliwe jest usunięcie tabeli z tego konta.

Kod do pobrania nazwy użytkownika z żądania to

Teraz Zapytanie byłoby coś takiego (aby przeszukać tabelę uczniów)

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

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

Zapytanie wynikowe staje się

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

Ponieważ dane wejściowe użytkownika nie są sanitized, powyższe zapytanie jest manipulowane do 2 części

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

DROP TABLE STUDENTS; --

Double dash ( -- ) skomentuje pozostałą część zapytania.

Jest to niebezpieczne, ponieważ może unieważnić uwierzytelnianie hasłem, jeśli jest obecne

Pierwszy wykona normalne wyszukiwanie.

Drugi upuści tabelę uczeń, jeśli konto ma wystarczające uprawnienia (generalnie konto administratora szkoły uruchomi takie zapytanie i będzie miało uprawnienia wymienione powyżej).

 5
Author: vivek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-11 16:56:24