Yii框架作为主流的PHP开发框架,提供了完善的数据库操作机制,但如果开发者不规范使用SQL拼接方式,依然可能出现SQL注入漏洞,而参数绑定与预处理是最有效的防护手段。

SQL注入在Yii框架中的常见产生场景
很多开发者在编写数据库查询逻辑时,会直接拼接用户输入的变量到SQL语句中,比如下面的错误示例:
<?php // 错误示例:直接拼接用户输入的变量到SQL语句 $userId = $_GET['user_id']; $sql = "SELECT * FROM user WHERE id = " . $userId; $command = Yii::$app->db->createCommand($sql); $result = $command->queryAll(); ?>
如果攻击者传入的user_id参数是1 OR 1=1,最终执行的SQL会变成SELECT * FROM user WHERE id = 1 OR 1=1,直接查询出所有用户数据,造成信息泄露。
Yii框架的参数绑定实现方式
Yii的数据库操作类支持通过命名参数或者问号占位符的方式进行参数绑定,框架会自动对参数进行转义处理,避免恶意内容被当作SQL指令执行。
使用命名参数绑定
命名参数以冒号开头,适合参数较多时的场景,代码可读性更强:
<?php
// 正确示例:使用命名参数绑定
$userId = $_GET['user_id'];
$sql = "SELECT * FROM user WHERE id = :user_id AND status = :status";
$command = Yii::$app->db->createCommand($sql);
// 绑定参数,框架会自动转义
$command->bindValue(':user_id', $userId);
$command->bindValue(':status', 1);
$result = $command->queryAll();
?>
使用问号占位符绑定
问号占位符按照参数顺序绑定,适合参数较少的简单查询场景:
<?php // 正确示例:使用问号占位符绑定 $userId = $_GET['user_id']; $sql = "SELECT * FROM user WHERE id = ? AND status = ?"; $command = Yii::$app->db->createCommand($sql); // 按顺序绑定参数,第一个参数是占位符索引,第二个是参数值 $command->bindValue(1, $userId); $command->bindValue(2, 1); $result = $command->queryAll(); ?>
Yii框架的预处理语句使用
预处理语句会先将SQL模板发送到数据库编译,之后传入的参数只会作为数据处理,不会被解析为SQL指令,比普通参数绑定安全性更高,也适合重复执行的查询场景。
Yii中可以通过prepare方法启用预处理,示例如下:
<?php
// 预处理语句示例
$userId = $_GET['user_id'];
$sql = "SELECT * FROM user WHERE id = :user_id";
// 准备预处理语句
$command = Yii::$app->db->createCommand($sql)->prepare();
// 绑定参数并执行
$command->bindParam(':user_id', $userId);
$command->execute();
$result = $command->queryAll();
// 重复执行时只需要重新绑定参数即可,不需要重新编译SQL
$userId = 2;
$command->bindParam(':user_id', $userId);
$command->execute();
$result2 = $command->queryAll();
?>
Active Record场景下的防护方式
Yii的Active Record是常用的数据模型操作方式,其内置的查询构造器已经默认使用了参数绑定,只要不直接拼接SQL片段,就可以避免注入风险:
<?php
// Active Record正确用法,不会存在注入风险
$userId = $_GET['user_id'];
// 查询构造器会自动处理参数绑定
$user = User::find()->where(['id' => $userId, 'status' => 1])->one();
// 错误用法:直接拼接where条件
// $user = User::find()->where("id = " . $userId)->one(); // 存在注入风险
?>
防护注意事项
- 所有用户输入的变量,只要参与SQL逻辑,都必须使用参数绑定或预处理,不能直接拼接
- 不要使用
Yii::$app->db->quoteValue手动转义后拼接,该方法仅适合特殊情况,不如参数绑定可靠 - 如果使用原生SQL查询,必须检查所有拼接的变量是否经过安全处理
- 定期审计项目中的数据库查询代码,排查直接拼接SQL的隐患