Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Security 如何从;“博比表”;XKCD漫画作品?_Security_Validation_Sql Injection - Fatal编程技术网

Security 如何从;“博比表”;XKCD漫画作品?

Security 如何从;“博比表”;XKCD漫画作品?,security,validation,sql-injection,Security,Validation,Sql Injection,看看: (来源:) 此SQL的作用是: Robert'); DROP TABLE STUDENTS; -- 我知道'和--都是用来评论的,但是这个词不是也会被评论,因为它是同一行的一部分吗?它会删除学生表。 学校程序中的原始代码可能看起来像 q = "INSERT INTO Students VALUES ('" + FNMName.Text + "', '" + LName.Text + "')"; 这是一种将文本输入添加到查询中的天真方法,正如您将看到的,这是非常糟糕的 在名字、中间名

看看:

(来源:)

此SQL的作用是:

Robert'); DROP TABLE STUDENTS; --

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

它会删除学生表。

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

q = "INSERT INTO Students VALUES ('" + FNMName.Text + "', '" + LName.Text + "')";
这是一种将文本输入添加到查询中的天真方法,正如您将看到的,这是非常糟糕的

在名字、中间名文本框FNMName.Text(即
Robert')中的值之后;落桌学生--
)和姓氏文本框LName.Text(我们称之为
Derper
)与查询的其余部分连接在一起,结果实际上是两个查询,由(分号)分隔。第二个查询已被注入第一个查询中。当代码对数据库执行此查询时,它将如下所示

INSERT INTO Students VALUES ('Robert'); DROP TABLE Students; --', 'Derper')
用简单的英语,大致可以翻译为两个查询:

将名称值为“Robert”的新记录添加到Students表中

删除学生表

超过第二个查询的所有内容都是:
--',“Derper”)

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


再次编辑根据《代码》的精明评论结束查询,但不开始注释。然后,它删除students表,并注释应该执行的查询的其余部分。

SQL中的
字符用于字符串常量。在本例中,它用于结束字符串常量,而不用于注释。

数据库的编写者可能做了一个

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

如果学生的名字是给定的,则用名字“Robert”进行选择,然后删除表格。“-”部分将给定查询的其余部分更改为注释。

假设该名称用于变量,
$name

然后运行此查询:

INSERT INTO students (name) VALUES ('Robert'); DROP TABLE STUDENTS --')
代码错误地将用户提供的任何内容作为变量放置

您希望SQL为:

插入学生值('Robert Tables`)

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

插入学生价值观(“罗伯特”);投递台学生;——)

你得到的是:

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

--
只注释行的其余部分。

在本例中,
'
不是注释字符。它用于分隔字符串文字。这位喜剧艺术家寄希望于这样一个想法,即所讨论的学校在某个地方有动态sql,看起来像这样:

$sql = "INSERT INTO `Students` (FirstName, LastName) VALUES ('" . $fname . "', '" . $lname . "')";
void createStudent(String name) {
    database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
}
Select *
From Students
Where (Name = '<NameGetsInsertedHere>')
SELECT * FROM users WHERE username='peter' and (password='secret')
因此,现在
字符在程序员预期之前结束字符串文字。与
相结合
character结束语句,攻击者现在可以添加(注入)他们想要的任何sql。最后的
--
注释用于确保原始语句中的任何剩余sql不会阻止查询在服务器上编译


FWIW,我还认为这部漫画有一个重要的细节是错误的:如果你像漫画所暗示的那样,对数据库输入进行清理,那么你仍然在做错误的事情。相反,您应该考虑隔离数据库输入,正确的方法是通过参数化查询/准备语句。

假设您天真地编写了一个学生创建方法,如下所示:

$sql = "INSERT INTO `Students` (FirstName, LastName) VALUES ('" . $fname . "', '" . $lname . "')";
void createStudent(String name) {
    database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
}
Select *
From Students
Where (Name = '<NameGetsInsertedHere>')
SELECT * FROM users WHERE username='peter' and (password='secret')
有人输入名字
Robert');落桌学生--

在数据库上运行的是以下查询:

INSERT INTO students (name) VALUES ('Robert'); DROP TABLE STUDENTS --')
分号结束insert命令并开始另一个命令;注释掉了行的其余部分。已执行DROP TABLE命令


这就是为什么绑定参数是件好事。

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

妈妈认为数据库程序员发出了如下请求:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('$firstName', '$lastName');
(例如)添加新的student,其中
$xxx
变量内容直接从HTML表单中取出,而不检查格式或转义特殊字符

因此,如果
$firstName
包含
Robert');落桌学生--数据库程序将直接在数据库上执行以下请求:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('Robert'); DROP TABLE students; --', 'XKCD');
它将提前终止insert语句,执行破解者想要的任何恶意代码,然后注释掉可能存在的任何剩余代码


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

单引号是字符串的开头和结尾。分号是语句的结尾。所以如果他们在做这样的选择:

$sql = "INSERT INTO `Students` (FirstName, LastName) VALUES ('" . $fname . "', '" . $lname . "')";
void createStudent(String name) {
    database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
}
Select *
From Students
Where (Name = '<NameGetsInsertedHere>')
SELECT * FROM users WHERE username='peter' and (password='secret')

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

正如大家已经指出的那样,
关闭原始语句,然后第二条语句紧跟其后。大多数框架,包括PHP等语言,现在都有默认的安全设置,不允许在一个SQL字符串中包含多个语句。例如,在PHP中,使用
mysqli\u multi\u query
函数只能在一个SQL字符串中运行多个语句

但是,您可以通过SQL注入操作现有SQL语句,而无需添加第二条语句。假设您有一个登录系统,它通过以下简单的选择检查用户名和密码:

$query="SELECT * FROM users WHERE username='" . $_REQUEST['user'] . "' and (password='".$_REQUEST['pass']."')";
$result=mysql_query($query);
如果您提供
peter
作为用户名,
secret
作为密码,则生成的SQL字符串如下所示:

$sql = "INSERT INTO `Students` (FirstName, LastName) VALUES ('" . $fname . "', '" . $lname . "')";
void createStudent(String name) {
    database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
}
Select *
From Students
Where (Name = '<NameGetsInsertedHere>')
SELECT * FROM users WHERE username='peter' and (password='secret')
一切都很好。现在假设您提供这个字符串作为