在 PHP 中使用准备好的语句/存储过程时如何保护自己免受 SQL 注入?
Posted
技术标签:
【中文标题】在 PHP 中使用准备好的语句/存储过程时如何保护自己免受 SQL 注入?【英文标题】:How do protect yourself against SQL injection when using prepared statements/store procedures in PHP? 【发布时间】:2011-09-25 20:52:07 【问题描述】:自从阅读Is mysql_real_escape_string enough to Anti SQL Injection? 后,我一直在研究如何最好地防止 php/mysql 中的 sql 注入,而不仅仅是使用 mysqli/mysql 真正的转义。
我看过这个很好的帖子How can I prevent SQL injection in PHP?
我曾经在桌面/内部工具上做很多 ms sql server 的工作,我们总是编写存储过程来防止这种情况发生,所以我使用 PDO http://php.net/manual/en/pdo.prepared-statements.php 阅读了 PHP/mysql 中的等价物
上面有一行:
prepared statements 的参数不需要引用;驱动程序会自动处理这个。如果应用程序专门使用预准备语句,开发人员可以确定不会发生 SQL 注入(但是,如果查询的其他部分是使用非转义输入构建的,则 SQL 注入仍然是可能的)。
我一直相信 PDO 确实可以防止 sql 注入攻击,所以任何人都可以提供一个从安全角度来看 PDO 不够用的实例吗?
【问题讨论】:
【参考方案1】:决定性的不是您使用的结构(存储过程、准备好的语句等),而是您是否在任何时候使用未经检查的用户输入将 SQL 连接在一起。例如,您可以在存储过程中执行动态 SQL,在这种情况下危险仍然存在。
最简单的方法(从避免注入的角度来看)是使用带有绑定变量的 SP 或 PS:这些不需要检查,因为它们将被识别为预定义占位符内的值。
【讨论】:
【参考方案2】:您仍然可以从存储过程中获取 SQL 注入,这些存储过程在内部使用 PREPARE 语法(在 MySQL 中)来创建动态 SQL 语句。
这些需要非常小心地完成,必要时使用 QUOTE()。
理想情况下,我们不需要在存储例程中使用 PREPARE,但在某些情况下,它会变得非常难以避免:
在 MySQL 5.5 之前,LIMIT 子句不能使用非常量值。 IN() 子句中使用的列表不能(明智地)参数化,因此如果使用此模式,则需要使用动态 SQL 有时需要使用动态生成的 ORDER BY 子句。等
在需要使用 PREPARE 的情况下,我会按优先顺序推荐:
如果某物是 INT 类型(等),则它不易受到 SQL 注入的影响,您可以毫无问题地将值放入查询中(例如,对于 LIMIT) 字符串值可以放在 EXECUTE 之前的 @variable 中,或者传递到 EXECUTE 子句中 需要检查列表值(例如 IN())的有效性。 最后,QUOTE() 可用于引用字符串值,这在某些情况下很有用【讨论】:
以上是关于在 PHP 中使用准备好的语句/存储过程时如何保护自己免受 SQL 注入?的主要内容,如果未能解决你的问题,请参考以下文章