看看:

(来源:https://xkcd.com/327/)

这个SQL做什么:

Robert'); DROP TABLE STUDENTS; --

我知道'和——都是用来评论的,但是DROP这个词不是也会被评论吗?因为它是同一行的一部分。


当前回答

在本例中,'不是注释字符。它用于分隔字符串字面量。漫画艺术家的想法是,学校在某个地方有动态sql,看起来像这样:

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

现在'字符在程序员期望它之前结束了字符串字面量。结合;字符来结束语句,攻击者现在可以添加(注入)任何他们想要的SQL。末尾的——注释是为了确保原始语句中任何剩余的sql都不会阻止在服务器上编译查询。

FWIW,我还认为漫画中有一个重要的细节是错误的:如果你像漫画中建议的那样清理数据库输入,你仍然是错的。相反,您应该考虑隔离数据库输入,正确的方法是通过参数化查询/准备好的语句。

其他回答

进行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。如果他记对了你的桌名,他们就会把你的桌子清空!(这是非常容易brut force这个URL与简单的脚本)

您的查询应该是这样的……

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

使用PDO的PHP易受攻击代码示例:

<?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! :) *************/
...

它删除了学生表。

学校程序的原始代码可能看起来像这样

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

这是向查询中添加文本输入的最简单的方法,非常糟糕,正如您将看到的那样。

值从第一个名字,中间名文本框FNMName。文本(是罗伯特的);降表学生;——)和姓氏文本框LName。文本(让我们称之为Derper)连接到查询的其余部分,结果实际上是两个查询由语句结束符(分号)分开。第二个查询已注入到第一个查询中。当代码对数据库执行此查询时,它将如下所示

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

简单地说,就是这两个问题:

在student表中添加一条Name值为'Robert'的新记录

and

删除Students表

第二个查询之后的所有内容都被标记为注释:——','Derper')

学生名字中的'不是注释,而是结束字符串分隔符。因为学生的名字是一个字符串,所以在语法上需要它来完成假设的查询。只有当注入的SQL查询结果为有效SQL时,注入攻击才有效。

根据dan04的评论再次编辑

单引号是字符串的开始和结束。分号是语句的结束。如果他们做这样的选择:

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

SQL将变成:

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

在某些系统上,select语句会先运行,然后是drop语句!信息是:不要嵌入值到你的SQL。而是使用参数!

不,'在SQL中不是注释,而是分隔符。

妈妈假设数据库程序员的请求是这样的:

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

(例如)添加新的student,其中$xxx变量内容直接从HTML表单中取出,不检查格式也不转义特殊字符。

如果$firstName包含Robert');DROP TABLE student;——数据库程序将直接在DB上执行以下请求:

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

ie。它会提前终止插入语句,执行黑客想要的任何恶意代码,然后注释掉可能存在的任何剩余代码。

嗯,我太慢了,我已经看到了8个答案在我之前的橙色带…:-)似乎是一个流行的话题。

');结束查询,不开始注释。然后它删除students表,并注释本该执行的其余查询。