看看:

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

这个SQL做什么:

Robert'); DROP TABLE STUDENTS; --

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


当前回答

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

其他回答

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

不,'在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个答案在我之前的橙色带…:-)似乎是一个流行的话题。

假设名称用于变量$ name。然后运行这个查询:

INSERT INTO Students VALUES ( '$Name' )

该代码错误地将用户提供的任何内容作为变量。你希望SQL是:

插入学生价值观(“罗伯特表格”)

但聪明的用户可以提供他们想要的任何东西:

INSERT INTO Students VALUES ('Robert');DROP TABLE Students;——”)

你得到的是:

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

——only注释该行的其余部分。

博士TL;

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

这将删除student表。

(这个回答中的所有代码示例都是在PostgreSQL 9.1.2数据库服务器上运行的。)

为了弄清楚发生了什么,让我们尝试一个只包含name字段的简单表,并添加一行:

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)

当我们将Little Bobby Tables的名字插入到表中时会发生什么?

--                            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代码的执行。这可以在应用程序级别上完成,一些参数化查询的实现通过清除输入来操作。

但是,在应用程序级别上清除输入可能不会阻止更高级的SQL注入技术。例如,有一些方法可以绕过mysql_real_escape_string PHP函数。为了增加保护,许多数据库系统支持预处理语句。如果在后端正确地实现,准备语句可以通过将数据输入从语义上与命令的其余部分分开来使SQL注入成为不可能。

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