
本文共 2893 字,大约阅读时间需要 9 分钟。
PHP安全:SQL注入漏洞防护
SQL注入是一种严重的安全漏洞,能够直接危及数据库和应用的安全性。作为开发者,我们需要采取有效措施来防止这种攻击。以下将详细介绍如何在PHP中使用MySQL预编译技术和传统防护方法来应对SQL注入威胁。
1. MySQL 预编译处理
MySQL 提供了预编译功能,可以有效隔离和执行 SQL 语句,避免恶意输入直接执行成代码。预编译分为三步:编译、执行和释放。
编译准备语句
使用prepare
语句将 SQL 语句编译并存储为准备语句。例如:prepare test from 'insert into hacker select ?, ? ';
返回的状态可以被引用并重复使用。
执行预编译语句
将参数绑定后执行预编译语句。例如:execute test using @name, @email, @password, @status;
使用 execute
语句以 @variable
格式传递参数。
释放和管理预编译语句
使用deallocate prepare test
释放预编译语句,避免占用资源。可以通过设置 max_prepared_stmt_count
控制全局预编译语句的数量:set @global.max_prepared_stmt_count = 100;
预编译防护的优势
预编译将 SQL 语句和数据分开处理,避免了跨 Injection 攻击。通过工具如Wireshark,可以监控预编译和参数的网络传输情况。2. PHP 中的预编译防护
在 PHP 中,推荐使用 PDO(PHP 数据对象扩展)或 MySQLi 来实现预编译处理。
2.1 PDO 的预编译示例
PDO 提供了对预编译的支持,通过设置适当的属性可以确保服务器端真正执行预编译语句。
$dns = 'mysql:dbname=safe;host=127.0.0.1';try { $pdo = new PDO('pdo://'.$dns, 'root', ''); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->query('set names utf8'); $sql = 'insert into hacker(name, email) values(:name, :email)'; $stmt = $pdo->prepare($sql); $name = 'hacker'; $email = 'safe@ptpress.com.cn'; $stmt->bindParam(':name', $name, PDO::PARAM_STR); $stmt->bindParam(':email', $email, PDO::PARAM_STR); $stmt->execute(); if ($stmt->errorCode() == 0) { echo "数据插入成功"; } else { echo "错误:" . $stmt->errorInfo(); print_r($stmt->errorInfo()); } $stmt->close(); $pdo->close();} catch(PDOException $e) { echo "数据库连接失败:" . $e->getMessage();}
2.2 MySQLi 的预编译示例
MySQLi 提供了与 PDO 相似的功能,同样支持预编译技术。
$mysqli = new mysqli('localhost', 'root', '', 'safe');if ($mysqli->connect_errno) { printf("Connect failed: %s", $mysqli->connect_error); exit();}$mysqli->query('set names utf8');$sql = 'insert into hacker(name, email) values(?, ?)';$stmt = $mysqli->prepare($sql);$name = 'hacker';$email = 'safe@ptpress.com.cn';$stmt->bind_param('ss', $name, $email);$result = $stmt->execute();if (!$result) { echo "错误:" . $mysqli->error;} else { echo "数据插入成功";}$stmt->close();$mysqli->close();
2.3 预编译的核心优势
预编译的核心作用是通过将 SQL 语句和数据分离,从根本上杜绝 SQL 注入威胁。客户端只需发送参数,避免了恶意输入直接构造和执行 SQL 命令。
3. 校验和过滤(传统防护方法)
在某些情况下,预编译可能无法适用或配置复杂,传统防护方法仍然具有重要作用。
3.1 输入校验
数据类型检查:确保输入数据类型与业务逻辑一致。例如:
$id = isset($_GET['id']) ? $_GET['id'] : 1;if (!is_int($id)) { die('非法的数据类型');}
数据范围验证:检查输入数据是否在合理范围内。例如:
if ($id <= 0) { die('输入超出范围');}
SQL 拼接校验:拼接 SQL 时,进行语法检查。
3.2 特殊字符过滤
使用 preg_replace
或类似的工具过滤 SQL 特殊字符。例如:
function removeSpecialChar($param) { return preg_replace(['~"]'). machAll($param);}$name = removeSpecialChar($_GET['name']);
避免 piercing SQL injection。
3.3 禁用魔术引号
PHP 提供的魔术引号选项 (magic_quotes_gpc
) 不建议开启,因为 RSnake 等工具已有绕过方法。
4. 宽字节注入防护
使用 mysql_real_escape_string
进行输入的宽字节字符转义,数据库需先设置字符集为 GBK 或 Binary:
mysql_query('SET NAMES "gbk"'); kde Wei;ID 3: protect against multibyte注入。
发表评论
最新留言
关于作者
