PDO 准备好的语句有多安全
Posted
技术标签:
【中文标题】PDO 准备好的语句有多安全【英文标题】:how safe are PDO prepared statements 【发布时间】:2010-11-21 19:41:05 【问题描述】:不久前开始使用 PDO 准备语句,据我了解,它为您完成了所有转义/安全。
例如,假设 $_POST['title'] 是一个表单域。
$title = $_POST['title'];
$query = "insert into blog(userID, title) values (?, ?)"
$st = $sql->prepare($query);
$st->bindParam(1, $_SESSION['user']['userID'], PDO::PARAM_INT);
$st->bindParam(2, $title);
$st->execute();
这真的安全吗?我还需要做什么吗?我还需要考虑什么?
谢谢。
【问题讨论】:
【参考方案1】:严格来说,实际上不需要转义,因为参数值永远不会插入到查询字符串中。
查询参数的工作方式是在您调用prepare()
时将查询发送到数据库服务器,而稍后在您调用execute()
时发送参数值。因此它们与查询的文本形式分开。永远不会有 SQL 注入的机会(前提是 PDO::ATTR_EMULATE_PREPARES
为假)。
是的,查询参数可以帮助您避免这种形式的安全漏洞。
它们是否 100% 证明可以防止任何安全漏洞?不,当然不。您可能知道,查询参数仅代替 SQL 表达式中的单个文字值。您不能让单个参数替代值列表,例如:
SELECT * FROM blog WHERE userid IN ( ? );
您不能使用参数来使表名或列名动态化:
SELECT * FROM blog ORDER BY ?;
您不能将参数用于任何其他类型的 SQL 语法:
SELECT EXTRACT( ? FROM datetime_column) AS variable_datetime_element FROM blog;
因此,在很多情况下,您必须在prepare()
调用之前将查询作为字符串进行操作。在这些情况下,您仍然需要仔细编写代码以避免 SQL 注入。
【讨论】:
LIKE ?
也是有效的,但您应该转义用于匹配的字符。
关于“从来没有机会进行 SQL 注入(假设 PDO::ATTR_EMULATE_PREPARES 为假)。”,这是否意味着 PDO 模拟准备不如数据库驱动程序的本地准备安全?如果有,为什么?
使用 PDO 准备注入的一个很好的例子(由于这个答案中提到的限制)是最近的 drupal 漏洞sektioneins.de/advisories/…
@thelastshadow,感谢您提供的真实示例!大家升级你的 Drupal!【参考方案2】:
对 SQL 注入是安全的。
有几件事是不安全的:
拒绝服务(导致创建过多行) 跨站点脚本攻击(如果标题曾经回显给其他用户)安全不仅仅是防止 SQL 注入。
【讨论】:
请贡献。如果标题回显给另一个用户,你是什么意思? 假设您将博客文章的标题存储在数据库中,其他用户可以查看这些文章。然后是潜在的跨站点脚本攻击,恶意用户可以制作包含 html 的标题,以将恶意脚本嵌入到页面中,因为它显示给您网站的其他用户。【参考方案3】:关于 SQL 注入,我相信这是您可以获得的最安全的方法,特别是如果您使用像 PDO::PARAM_INT 这样的常量。
【讨论】:
这个“特别”需要 IMO 澄清一下。你可能不想说它是 95% 安全的,但如果你使用常量,它是 100% 安全的。如果没有常量,它不是 100% 安全的,它是不安全的。如果它是 100%,那么使用常量就不是“特别”安全的。使用常量和不使用常量的安全区别是什么?【参考方案4】:既然提到了XSS,我觉得也可以看看使用诸如输入清理类http://www.phpclasses.org/browse/package/2189.html之类的东西来防止XSS攻击。
【讨论】:
以上是关于PDO 准备好的语句有多安全的主要内容,如果未能解决你的问题,请参考以下文章