准备好的语句如何帮助我们防止SQL注入攻击?

维基百科说:

预处理语句对SQL注入具有弹性,因为 参数值,稍后使用不同的 协议,不需要正确转义。如果原始语句 模板不能从外部输入派生,SQL注入不能 发生。

我不太明白其中的原因。如何用简单的英语和一些例子来简单地解释?


当前回答

其思想非常简单——查询和数据分别发送到数据库服务器。 这是所有。

SQL注入问题的根源在于代码和数据的混合。

事实上,我们的SQL查询是一个合法的程序。 我们正在动态地创建这样一个程序,动态地添加一些数据。因此,数据可能会干扰程序代码,甚至改变它,正如每个SQL注入示例所显示的那样(所有PHP/Mysql中的示例):

$expected_data = 1;
$query = "SELECT * FROM users where id=$expected_data";

会产生一个常规查询吗

SELECT * FROM users where id=1

而这段代码

$spoiled_data = "1; DROP TABLE users;"
$query        = "SELECT * FROM users where id=$spoiled_data";

会产生恶意序列吗

SELECT * FROM users where id=1; DROP TABLE users;

它可以工作,因为我们直接将数据添加到程序主体中,它成为程序的一部分,因此数据可能会改变程序,并且根据传递的数据,我们将有一个常规输出或用户删除的表。

而对于准备好的语句,我们不改变我们的程序,它保持不变 这就是重点。

我们首先向服务器发送一个程序

$db->prepare("SELECT * FROM users where id=?");

其中数据被一些称为参数或占位符的变量所取代。

注意,完全相同的查询被发送到服务器,其中没有任何数据!然后我们将数据与第二个请求一起发送,本质上与查询本身分离:

$db->execute($data);

所以它不会改变我们的程序,造成任何伤害。 很简单,不是吗?

我唯一需要补充的是,每个手册中都省略了:

预准备语句只能保护数据文字,但不能与任何其他查询部分一起使用。 因此,一旦我们必须添加一个动态标识符——例如,一个字段名——预处理语句就无法帮助我们。这件事我最近已经解释过了,我就不再重复了。

其他回答

关键短语是不需要正确转义。这意味着你不需要担心人们试图插入破折号、撇号、引号等等……

一切都为你安排好了。

基本上,通过准备好的语句,来自潜在黑客的数据被视为数据——它不可能与应用程序SQL混合和/或被解释为SQL(当传入的数据直接放入应用程序SQL时可能发生)。

这是因为预处理语句首先“准备”SQL查询,以找到一个有效的查询计划,然后发送可能来自表单的实际值——在查询实际执行的时候。

更多信息请点击这里:

准备好的语句和SQL注入

根本原因#1 -分隔符问题

Sql注入是可能的,因为我们使用引号来分隔字符串,也作为字符串的一部分,使得有时无法解释它们。如果我们有不能在字符串数据中使用的分隔符,sql注入就永远不会发生。解决分隔符问题可以消除sql注入问题。结构查询可以做到这一点。

根本原因#2 -人性,人们是狡猾的,一些狡猾的人是恶意的,所有的人都会犯错误

sql注入的另一个根本原因是人性。人,包括程序员,都会犯错误。当您在结构化查询中犯错误时,它不会使您的系统容易受到sql注入的攻击。如果不使用结构化查询,错误可能会产生sql注入漏洞。

结构化查询如何解决SQL注入的根本原因

结构化查询解决了分隔符问题,方法是将sql命令放在一个语句中,将数据放在一个单独的编程语句中。编程语句创建所需的分离。

Structured queries help prevent human error from creating critical security holes. With regard to humans making mistakes, sql injection cannot happen when structure queries are used. There are ways of preventing sql injection that don't involve structured queries, but normal human error in that approaches usually leads to at least some exposure to sql injection. Structured Queries are fail safe from sql injection. You can make all the mistakes in the world, almost, with structured queries, same as any other programming, but none that you can make can be turned into a ssstem taken over by sql injection. That is why people like to say this is the right way to prevent sql injection.

所以,你已经了解了sql注入的原因,以及在使用sql注入时不可能使用sql注入的本质结构化查询。

简单的例子:

  "select * from myTable where name = " + condition;

如果用户输入是:

  '123'; delete from myTable; commit;

查询将像这样执行:

  select * from myTable where name = '123'; delete from myTable; commit;

其思想非常简单——查询和数据分别发送到数据库服务器。 这是所有。

SQL注入问题的根源在于代码和数据的混合。

事实上,我们的SQL查询是一个合法的程序。 我们正在动态地创建这样一个程序,动态地添加一些数据。因此,数据可能会干扰程序代码,甚至改变它,正如每个SQL注入示例所显示的那样(所有PHP/Mysql中的示例):

$expected_data = 1;
$query = "SELECT * FROM users where id=$expected_data";

会产生一个常规查询吗

SELECT * FROM users where id=1

而这段代码

$spoiled_data = "1; DROP TABLE users;"
$query        = "SELECT * FROM users where id=$spoiled_data";

会产生恶意序列吗

SELECT * FROM users where id=1; DROP TABLE users;

它可以工作,因为我们直接将数据添加到程序主体中,它成为程序的一部分,因此数据可能会改变程序,并且根据传递的数据,我们将有一个常规输出或用户删除的表。

而对于准备好的语句,我们不改变我们的程序,它保持不变 这就是重点。

我们首先向服务器发送一个程序

$db->prepare("SELECT * FROM users where id=?");

其中数据被一些称为参数或占位符的变量所取代。

注意,完全相同的查询被发送到服务器,其中没有任何数据!然后我们将数据与第二个请求一起发送,本质上与查询本身分离:

$db->execute($data);

所以它不会改变我们的程序,造成任何伤害。 很简单,不是吗?

我唯一需要补充的是,每个手册中都省略了:

预准备语句只能保护数据文字,但不能与任何其他查询部分一起使用。 因此,一旦我们必须添加一个动态标识符——例如,一个字段名——预处理语句就无法帮助我们。这件事我最近已经解释过了,我就不再重复了。