Como funciona a injecção de SQL da revista" Bobby Tables " XKCD?

só a olhar para:

XKCD Strip(Fonte: https://xkcd.com/327/)

o que faz este SQL:

Robert'); DROP TABLE STUDENTS; --

Eu sei que ambos ' e -- são para Comentários, mas a palavra DROP não é comentada também uma vez que faz parte da mesma linha?

Author: Floern, 2008-12-02

12 answers

Deixa cair a mesa dos alunos.

O código original do programa da escola deve parecer algo parecido com ...
q = "INSERT INTO Students VALUES ('" + FNMName.Text + "', '" + LName.Text + "')";

Esta é a maneira ingênua de adicionar entrada de texto em uma consulta, e é Muito Ruim, como você verá.

Após os valores do primeiro nome, o nome do meio textbox FNMName.Text (que é Robert'); DROP TABLE STUDENTS; --) e o último nome textbox LName.Texto (vamos chamá-lo Derper) são concatenados com o resto da consulta, o resultado é agora realmente duas consultas separadas pelo terminador de declarações (ponto e vírgula). A segunda consulta foi injectada na primeira. Quando o código executa esta consulta na base de dados, ela se parecerá com este

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

Que, em Inglês claro, se traduz aproximadamente para as duas perguntas:

Adicione um novo registo à tabela de alunos com um valor de nome de 'Robert'

E

Apaguem os alunos. Quadro

Tudo depois da segunda consulta é marcado como um comentário: --', 'Derper')

O ' em nome do estudante não é um comentário, é o delimitador de texto final. Uma vez que o nome do estudante é uma string, é necessário sintaticamente para completar a consulta hipotética. Os ataques de injecção só funcionam quando a pesquisa SQL que injectam resulta em SQL válido.

Edição outra vez. Como por dan04'S astute comentário

 1032
Author: Will, 2017-05-23 12:02:58
Digamos que o nome foi usado numa variável. Você então executa esta consulta:
INSERT INTO Students VALUES ( '$Name' )

O código está a colocar erradamente qualquer coisa que o utilizador tenha fornecido como variável. Querias que o SQL fosse:

Inserir nos valores dos estudantes ('tabelas Robert` )

Mas um utilizador inteligente pode fornecer o que quiser.

Inserir nos valores dos estudantes ('[11]}Robert'); retirar os estudantes da tabela; --' )

O que você tem riz:

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

O -- apenas comenta o resto da linha.

 558
Author: sinoth, 2018-05-24 13:45:43

Como todos já salientaram, o '); encerra a declaração original e depois segue-se uma segunda declaração. A maioria dos frameworks, incluindo linguagens como PHP, já têm configurações de segurança padrão que não permitem múltiplas declarações em uma string SQL. Em PHP, por exemplo, você só pode executar várias declarações em uma string SQL usando a função mysqli_multi_query.

Pode, no entanto, manipular uma declaração SQL existente através de uma injecção SQL sem ter de adicionar um segundo instrucao. Digamos que tem um sistema de autenticação que verifica um nome de utilizador e uma senha com esta simples opção:

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

Se você indicar peter como o nome de utilizador e secret como a senha, a sequência de SQL resultante ficaria assim:

SELECT * FROM users WHERE username='peter' and (password='secret')
Está tudo bem. Agora imagine que você fornece este texto como a senha:
' OR '1'='1

Então a sequência de SQL resultante seria esta:

SELECT * FROM users WHERE username='peter' and (password='' OR '1'='1')
Isso permitir-lhe-ia aceder a qualquer conta sem saber a senha. Então tu ... não precisa ser capaz de usar duas declarações, a fim de usar a injeção SQL, embora você pode fazer coisas mais destrutivas se você é capaz de fornecer várias declarações.
 146
Author: Johannes Fahrenkrug, 2013-02-20 08:42:21

Não, ' não é um comentário em SQL, mas um delimitador.

A mãe disse que o programador da base de dados fez um pedido parecido com:
INSERT INTO 'students' ('first_name', 'last_name') VALUES ('$firstName', '$lastName');

(por exemplo) para adicionar o novo aluno, onde o conteúdo da variável $xxx foi retirado directamente de um formulário HTML, sem verificar o formato nem escapar de caracteres especiais.

SE $firstName contiver Robert'); DROP TABLE students; -- o programa da base de dados irá executar o seguinte pedido directamente no DB:

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

Ie. terminará no início da sequência inserida declaração, execute o código malicioso que o cracker quiser, e depois comente o resto do código que possa haver.

Sou muito lento, já vejo 8 respostas antes das minhas na banda laranja... :- ) Um tema popular, ao que parece.
 69
Author: PhiLho, 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;
                      ^

Isto deixa cair (apaga) a mesa dos estudantes.

(todos os exemplos de código nesta resposta foram executados em um servidor de banco de dados PostgreSQL 9.1.2.)

Para deixar claro o que está a acontecer, vamos tentar isto com uma tabela simples que contém apenas o campo Nome e adicionar uma única linha:

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

Vamos assumir que a aplicação usa o seguinte SQL para inserir dados na tabela:

INSERT INTO students VALUES ('foobar');

Substituir foobar pelo nome real do estudante. Uma operação de inserção normal seria assim:

--                            Input:   Nancy
school=> INSERT INTO students VALUES ('Nancy');
INSERT 0 1
Quando interrogamos a mesa, recebemos isto:
school=> SELECT * FROM students;
 name
-------
 John
 Nancy
(2 rows)
O que acontece quando colocarmos o nome do Bobby Tables na mesa?
--                            Input:   Robert'); DROP TABLE students; --
school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
INSERT 0 1
DROP TABLE

A injecção de SQL aqui é o resultado do nome do estudante que termina a declaração e inclui um comando separado {[[8]}; os dois traços no final da entrada destinam-se a comentar qualquer código que, de outra forma, causaria um erro. A última linha da a saída confirma que o servidor da base de dados deixou cair a tabela.

É importante notar que durante a operação INSERT a aplicação não está a verificar a entrada para quaisquer caracteres especiais, e está, portanto, a permitir a introdução arbitrária de dados no comando SQL. Isto significa que um usuário malicioso pode inserir, em um campo normalmente destinado à entrada do Usuário, símbolos especiais, tais como citações, juntamente com código SQL arbitrário para fazer com que o sistema de banco de dados para executá-lo, portanto SQL injecção.

O resultado?
school=> SELECT * FROM students;
ERROR:  relation "students" does not exist
LINE 1: SELECT * FROM students;
                      ^

A injecção de SQL é o equivalente a uma base de dados de uma execução de código arbitrária remota vulnerabilidade num sistema operativo ou aplicação. O impacto potencial de um ataque de injeção SQL bem sucedido não pode ser subestimado--dependendo do sistema de banco de dados e configuração da aplicação, ele pode ser usado por um atacante para causar a perda de dados (como neste caso), ganhar acesso não autorizado aos dados, ou até mesmo executar código arbitrário na própria máquina.

Como observado pela banda desenhada XKCD, uma maneira de proteger contra ataques de injeção SQL é sanitar entradas de banco de dados, como por exemplo, escapando de caracteres especiais, de modo que eles não podem modificar o comando SQL subjacente e, portanto, não podem causar a execução de código SQL arbitrário. Se você usar consultas parametrizadas, como por exemplo usando SqlParameter em ADO.NET, a entrada será, no mínimo, sancionada automaticamente para proteger contra SQL injeccao.

No entanto, desinfectar as entradas ao nível da aplicação não pode impedir técnicas mais avançadas de injecção de SQL. Por exemplo, existem maneiras de contornar a função mysql_real_escape_string PHP. Para proteção adicional, muitos sistemas de banco de dados de suporte declarações preparadas. Se correctamente implementado na infra-estrutura, as declarações preparadas podem tornar impossível a injecção de SQL tratando as entradas de dados semanticamente separadas do resto do comando.

 34
Author: bwDraco, 2018-06-11 03:16:49
Digamos que você ingenuamente escreveu um método de criação de estudantes como este:
void createStudent(String name) {
    database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
}
E alguém entra no nome Robert'); DROP TABLE STUDENTS; --

O que é executado na base de dados é esta consulta:

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

O ponto e vírgula termina o comando Inserir e inicia outro; o -- comenta o resto da linha. O comando DROP TABLE é executado...

É por isso que os parâmetros de ligação são uma coisa boa.
 27
Author: Dan Vinton, 2008-12-01 21:56:45

Uma única citação é o início e o fim de uma cadeia de caracteres. Um ponto e vírgula É o fim de uma declaração. Então, se eles estavam fazendo uma seleção como esta:

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

O SQL tornar-se-ia:

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

Em alguns sistemas, o select seria executado primeiro seguido pela declaração drop! A mensagem é: NÃO insira valores em seu SQL. Em vez disso, use parâmetros!

 24
Author: CodeAndCats, 2011-09-15 06:39:16

O {[[0]} termina a consulta, não inicia um comentário. Em seguida, ele deixa cair a mesa dos alunos e comenta o resto da consulta que deveria ser executada.

 16
Author: Jorn, 2010-04-12 08:18:28
O autor da base de dados provavelmente fez um ...
sql = "SELECT * FROM STUDENTS WHERE (STUDENT_NAME = '" + student_name + "') AND other stuff";
execute(sql);

Se o student_name é o indicado, que faz a selecção com o nome "Robert" e, em seguida, deixa cair a mesa. A parte " -- " muda o resto da consulta em um comentário.

 15
Author: Paul Tomblin, 2008-12-01 22:46:58

Neste caso, ' não é um carácter de comentário. É usado para delimitar literais de cordas. O artista cómico está a contar com a ideia de que a escola em questão tem um sql dinâmico algures que se parece com algo parecido com isto:

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

Então agora o personagem ' termina o texto literal antes que o programador o esperasse. Combinado com o ; character para terminar a Declaração, um atacante pode agora adicionar o que quiser sql. O -- comment no final é para ter certeza de que qualquer sql restante no a instrução original não impede a consulta de compilar no servidor.

{[[2]}FWIW, eu também acho que a cômica em questão tem um detalhe importante errado: se você está pensando em Limpar suas entradas de banco de dados, como a cômica sugere, você ainda está fazendo errado. Em vez disso, você deve pensar em termos de quarantining suas entradas de banco de dados, e a maneira correta de fazer isso é através de consultas parametrizadas.
 15
Author: Joel Coehoorn, 2014-12-11 15:24:44

O carácter ' em SQL é usado para constantes de cordas. Neste caso é usado para terminar a constante de string e não para comentar.

 14
Author: Rockcoder, 2010-04-12 08:17:38
É assim que funciona.: Vamos supor que o administrador está procurando registros do estudante
Robert'); DROP TABLE STUDENTS; --

Dado que a conta de administração tem privilégios elevados, é possível remover a tabela desta conta.

O código para obter o nome de utilizador do pedido é

Agora a consulta seria algo assim (para procurar na tabela estudantil)

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

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

A consulta resultante torna-se

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

Uma vez que a entrada do utilizador não é desinfectada, a consulta acima foi manipulada para 2 partes

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

DROP TABLE STUDENTS; --

O Double dash ( -- ) apenas comentará a parte restante da consulta.

Isto é perigoso porque pode anular a autenticação por senha, se estiver presente

O primeiro fará a busca normal.

O segundo irá deixar cair o estudante da tabela se a conta tiver privilégios suficientes (geralmente a conta de administração da escola irá executar essa consulta e terá os privilégios mencionados acima).

 5
Author: vivek, 2016-07-11 16:56:24