首页 > 后端开发 > php教程 > PDO 准备语句真的能免受 SQL 注入攻击吗?

PDO 准备语句真的能免受 SQL 注入攻击吗?

Susan Sarandon
发布: 2024-12-26 01:48:09
原创
548 人浏览过

Are PDO Prepared Statements Truly Safe from SQL Injection Attacks?

PDO 准备语句是否不受 SQL 注入影响?

虽然 PDO 文档表明准备语句消除了手动参数引用的需要,但答案是微妙的“是” ”。 PDO 默认模拟 MySQL 的准备语句,这种模拟有时会产生可利用的漏洞。

攻击向量

当连接编码涉及特定的易受攻击的字符集(例如 gbk)时,就会出现潜在的漏洞, cp932) 且满足以下条件:

  1. 数据库字符集使用 SET NAMES 设置(而不是 mysql_set_charset())。
  2. 客户端使用模拟准备语句(或 MySQL 服务器将其视为模拟的真实准备语句)。

在这种情况下,攻击者可以制作包含无效多字节字符的有效负载,并利用客户端上的预期字符集与连接的实际字符集之间的差异。这允许他们将不带引号的字符注入到生成的查询字符串中,从而导致潜在的 SQL 注入。

修复

预防:

  • 禁用模拟准备语句: $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
  • 使用 PDO DSN charset 参数设置字符编码(PHP >= 5.3.6): $pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=gbk ', $user, $password);
  • 避免易受攻击的编码:使用不易受此影响的字符集,如 UTF-8 或 Latin1

缓解:

  • 启用 NO_BACKSLASH_ESCAPES SQL 模式:这会改变字符转义的行为,从而缓解潜在的漏洞。

安全示例

以下代码片段说明了安全实践:

// PDO without emulated prepares
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("xbf' OR 1=1 /*"));

// PDO with DSN charset parameter
$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=gbk', $user, $password);
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("xbf' OR 1=1 /*"));

// MySQLi (always uses true prepared statements)
$mysqli->query('SET NAMES gbk');
$stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$param = "xbf' OR 1=1 /*";
$stmt->bind_param('s', $param);
$stmt->execute();
登录后复制

结论

如果正确使用并与安全实践结合使用,PDO 准备语句可以有效防止 SQL 注入。避免易受攻击的编码、禁用模拟准备或启用 NO_BACKSLASH_ESCAPES 模式以减轻潜在漏洞至关重要。

以上是PDO 准备语句真的能免受 SQL 注入攻击吗?的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板