使用参数如何防止SQL注入?
许多人说使用参数代替输入字符串(例如,来自网站用户)可以防止SQL注入。
但是我不明白,我的意思是“ drop database”字符串和在查询中使用的“ drop database”字符串有什么不同?
答案 0 :(得分:3)
SQL注入通过在RDBMS解析SQL语法之前修改SQL查询来起作用。
查询参数在解析完SQL后会发送到服务器 ,因此对于恶意值影响SQL语法的解析为时已晚。
查询参数只能解释为标量值,例如字符串。
答案 1 :(得分:3)
因为仅将“放置数据库”本身输入到字段中是不够的。您必须添加其他一些字符以说服SQL解释器终止上一条语句并开始一个新语句(以执行DROP)。除其他因素外,参数化将阻止此类序列通过SQL以预期的方式成功注入和解释。例如,'
之类的字符可能会关闭字符串,因此将对其进行转义,以便将其视为变量的一部分,而不是SQL的一部分。
具体地说,http://bobby-tables.com/about包含一个有效的示例。在该示例中,有一些PHP代码可在表中插入一行:
$sql = "INSERT INTO Students (Name) VALUES ('" . $studentName . "');";
execute_sql($sql);
如果将$studentName
设置为“ John”之类的正常值,则该代码产生的最终SQL字符串将是良性的:
INSERT INTO Students (Name) VALUES ('John');
同样,类似于您的示例,如果将$studentName
设置为“ DROP TABLE Students”,它仍然没有任何作用。最终的SQL将是:
INSERT INTO Students (Name) VALUES ('DROP TABLE Students');
没有伤害。
但是...如果$studentName
设置得更微妙,例如:
Robert'); DROP TABLE Students;--
最终的字符串如下:
INSERT INTO Students (Name) VALUES ('Robert'); DROP TABLE Students;--');
然后将其传递给SQL引擎,SQL引擎将其解释为两个语句(附带一个末尾的注释),并同时执行这两个语句,结果不愉快。
但是,如果$studentName
中的值已作为参数传递而不是仅连接到标准字符串,则最终查询将以
INSERT INTO Students (Name) VALUES ('Robert\'); DROP TABLE Students;--');
请注意,转义的'
位于中间,因此现在被视为字符串的一部分。它不再导致字符串在“ t”之后停止。
因此,在表的Name
字段中输入的内容将是
Robert'); DROP TABLE Students;--
DROP TABLE语句将不会执行,因为SQL解释器永远不会看到它-它只是将其视为要添加到表中的值的一部分。
参数化意味着参数值中的任何内容都仅被视为字符串(或可能为数字)-它永远不能逃逸到该字符串之外,并且被视为SQL语句本身的一部分。
进一步阅读:
How does the SQL injection from the "Bobby Tables" XKCD comic work?
可以帮助您更好地理解。
答案 2 :(得分:0)
请参阅有关sql注入攻击的示例:让我们假设这个伪代码:
myfunction(myuser)
{
sql="SELECT user, password FROM users WHERE user='"+myuser+"'"
return db.execute(sql)
}
通过此调用,攻击者将利用此漏洞获取表的所有密码:
myfunction("x' OR true OR 'a'='")
相反,如果程序员通过绑定变量执行查询:
myfunction(myuser)
{
sql="SELECT user, password FROM users WHERE user=?"
sql.setParam(1, myUser)
return db.execute(sql)
}
在这种情况下,对于攻击者而言,输入任何棘手的值都将是没有用的,因为数据库引擎将透明地对待值 100%,而不会允许其中的任何控制字符它。