关于许多有用的答案,我希望为该线程增加一些价值。
SQL注入是一种攻击,可以通过用户输入(由用户填充然后在查询中使用的输入)来完成。SQL注入模式是正确的查询语法,我们可以称之为:错误的查询是出于错误的原因,并且我们假设可能有一个错误的人试图获取影响安全性三原则(机密性)的秘密信息(绕过访问控制)。 ,完整性和可用性)。
现在,我们的观点是防止诸如SQL注入攻击之类的安全威胁,这个问题(如何使用PHP防止SQL注入攻击)更加现实,数据过滤或清除输入数据是在内部使用用户输入数据的情况这样的查询,不是使用PHP或任何其他编程语言,或者不是像更多人所推荐的那样使用现代技术(例如,准备好的语句或当前支持SQL注入预防的任何其他工具),是否认为这些工具不再可用?您如何保护您的应用程序?
我反对SQL注入的方法是:在将用户输入的数据发送到数据库之前(在任何查询中使用它之前),先清除它们。
数据过滤(将不安全数据转换为安全数据)
考虑到PDO和MySQLi不可用。您如何保护您的应用程序?你强迫我使用它们吗?除了PHP以外的其他语言呢?我更喜欢提供一般性的想法,因为它不仅可以用于特定的语言,而且可以用于更广泛的边界。
- SQL用户(限制用户特权):最常见的SQL操作是(SELECT,UPDATE,INSERT),那么,为什么将UPDATE特权赋予不需要的用户呢?例如,登录和搜索页面仅使用SELECT,那么,为什么在这些页面中以高特权使用DB用户?
规则:不要为所有特权创建一个数据库用户。对于所有SQL操作,您都可以将诸如(deluser,selectuser,updateuser)之类的方案创建为用户名,以便于使用。
请参阅最低特权原则。
数据过滤:在建立任何查询用户输入之前,应先对其进行验证和过滤。对于程序员来说,为每个用户输入变量定义一些属性很重要:
数据类型,数据模式和数据长度。(x和y)之间的数字字段必须使用确切的规则进行完全验证,对于字符串(文本)字段:模式就是这种情况,例如,用户名只能包含一些字符,让我们说[a-zA-Z0-9_-。]。长度在(x和n)之间变化,其中x和n(整数,x <= n)。
规则:创建精确的过滤器和验证规则对我来说是最佳做法。
使用其他工具:在这里,我也将与您同意准备好的语句(参数化查询)和存储过程。这里的缺点是这些方式需要大多数用户不具备的高级技能。这里的基本思想是区分SQL查询和内部使用的数据。这两种方法甚至都可以用于不安全的数据,因为此处的用户输入数据不会向原始查询添加任何内容,例如(any或x = x)。
有关更多信息,请阅读OWASP SQL注入预防备忘单。
现在,如果您是高级用户,则可以根据需要开始使用此防御,但是,对于初学者来说,如果他们不能快速实现存储过程并准备语句,那么最好尽可能过滤输入数据。
最后,让我们考虑一个用户在下面发送此文本,而不是输入他/她的用户名:
[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'
可以在没有任何准备好的语句和存储过程的情况下及早检查此输入,但是出于安全考虑,请在用户数据过滤和验证之后开始使用它们。
最后一点是检测意外行为,这需要更多的精力和复杂性。不建议在普通的Web应用程序中使用。
上面的用户输入中的意外行为是SELECT,UNION,IF,SUBSTRING,BENCHMARK,SHA和root。一旦检测到这些单词,就可以避免输入。
更新1:
一位用户评论说,这篇文章没有用,好!这是OWASP.ORG提供的内容:
主要防御措施:
选项1:使用准备好的语句(参数化查询)
选项2:使用存储过程
选项3:逃避所有用户提供的输入
附加防御:
还强制执行:最小特权
还执行:白名单输入验证
如您所知,声明某篇文章应有一个有效的论点支持,至少有一个参考!否则,将其视为攻击和不当索取!
更新2:
在PHP手册中,PHP:Prepared Statements-Manual:
转义和SQL注入
绑定变量将由服务器自动转义。服务器在执行之前将其转义的值插入到语句模板的适当位置。必须向服务器提供有关绑定变量类型的提示,以创建适当的转换。有关更多信息,请参见mysqli_stmt_bind_param()函数。
服务器内值的自动转义有时被认为是防止SQL注入的安全功能。如果正确地转义了输入值,则使用非准备的语句可以达到相同的安全性。
更新3:
我创建了测试用例,以了解在使用准备好的语句时PDO和MySQLi如何将查询发送到MySQL服务器:
PDO:
$user = "''1''"; // Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));
查询日志:
189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
189 Quit
MySQLi:
$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();
查询日志:
188 Prepare SELECT * FROM awa_user WHERE username =?
188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\''
188 Quit
显然,一条准备好的语句也在转义数据,仅此而已。
正如以上声明中所述,
服务器内值的自动转义有时被认为是防止SQL注入的安全功能。如果正确地转义了输入值,则使用非准备的语句可以实现相同的安全性
因此,这证明了intval()
在发送任何查询之前,对整数值进行数据验证是一个好主意。另外,在发送查询之前防止恶意用户数据是正确有效的方法。
请查看此问题以获取更多详细信息:PDO将原始查询发送到MySQL,而Mysqli发送已准备好的查询,两者都会产生相同的结果
参考文献:
- SQL注入备忘单
- SQL注入
- 信息安全
- 安全原则
- 资料验证