PHP中如何防止SQL注入

PHP中如何防止SQL注入

技术背景

SQL注入是一种常见的Web安全漏洞,攻击者通过在用户输入中插入恶意的SQL代码,从而篡改或获取数据库中的数据。在PHP应用中,防止SQL注入是保障数据安全的重要任务。

实现步骤

分离数据与SQL

避免SQL注入攻击的正确方法是将数据与SQL分离,使数据仅作为数据存在,不会被SQL解析器解释为命令。建议使用预准备语句和参数化查询,这能有效防止攻击者注入恶意SQL。

使用PDO(适用于任何支持的数据库驱动)

1
2
3
4
5
6
$stmt = $pdo->prepare('SELECT * FROM users WHERE name = :name');
$stmt->execute([ 'name' => $name ]);

foreach ($stmt as $row) {
// 处理$row
}

使用MySQLi(适用于MySQL)

  • PHP 8.2+
1
2
3
4
$result = $db->execute_query('SELECT * FROM users WHERE name = ?', [$name]);
while ($row = $result->fetch_assoc()) {
// 处理$row
}
  • PHP 8.1及以下
1
2
3
4
5
6
7
$stmt = $db->prepare('SELECT * FROM employees WHERE name = ?');
$stmt->bind_param('s', $name); // 's'指定变量类型为字符串
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// 处理$row
}

正确设置连接

PDO

使用PDO访问MySQL数据库时,默认不使用真正的预准备语句,需要禁用预准备语句的模拟。示例如下:

1
2
3
4
5
$dsn = 'mysql:dbname=dbtest;host=127.0.0.1;charset=utf8mb4';
$dbConnection = new PDO($dsn, 'user', 'password');

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

MySQLi

1
2
3
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // 错误报告
$dbConnection = new mysqli('127.0.0.1', 'username', 'password', 'test');
$dbConnection->set_charset('utf8mb4'); // 字符集

核心代码

插入操作示例(使用PDO)

1
2
$stmt = $db->prepare('INSERT INTO table (column) VALUES (:column)');
$stmt->execute(['column' => $value]);

动态查询的处理

对于动态查询,虽然可以对查询参数使用预准备语句,但查询的结构和某些特性无法参数化。此时,可使用白名单过滤来限制可能的值。

1
2
3
4
5
// 值白名单
// $dir只能为'DESC',否则为'ASC'
if (empty($dir) || $dir !== 'DESC') {
$dir = 'ASC';
}

最佳实践

  • 始终使用预准备语句和参数化查询,避免手动拼接SQL字符串。
  • 对用户输入进行严格的验证和过滤,确保输入的数据符合预期。
  • 采用MVC模式和框架,如CakePHP或CodeIgniter,利用其内置的安全机制。
  • 限制数据库用户的权限,遵循最小权限原则。

常见问题

预准备语句能否用于动态查询?

预准备语句可用于查询参数,但动态查询的结构和某些特性无法参数化。对于这些情况,建议使用白名单过滤。

手动转义字符串能否防止SQL注入?

手动转义字符串(如使用mysql_real_escape_string)已被证明不足以防止SQL注入,建议使用预准备语句。

预准备语句的性能如何?

如果在同一会话中多次执行相同的语句,预准备语句只会被解析和编译一次,能提高性能。但如果语句只执行一次,可能会有轻微的性能损失。


PHP中如何防止SQL注入
https://119291.xyz/posts/2025-05-13.php-sql-injection-prevention/
作者
ww
发布于
2025年5月13日
许可协议