浅谈 ThinkPHP 中的注入
字数 1031 2025-08-26 22:11:45
ThinkPHP 注入漏洞分析与防御指南
前言
ThinkPHP 作为国内流行的 PHP 框架,在 CMS 开发中被广泛使用。本文深入分析 ThinkPHP 不同版本中的 SQL 注入漏洞原理,帮助开发者理解漏洞成因并采取有效防御措施。
ThinkPHP 3.2.3 注入分析
漏洞原理
ThinkPHP 3.2.3 版本中,parseWhereItem 函数存在直接拼接 SQL 语句的安全隐患,特别是在使用 exp 表达式时。
漏洞代码分析
-
调用流程:
where()方法将参数存入options['where']find()方法调用select()select()调用buildSelectSql()生成 SQLbuildSelectSql()调用parseSql()解析 SQL 模板parseSql()调用parseWhere()处理 WHERE 条件parseWhere()最终调用parseWhereItem()处理具体条件
-
关键函数 - parseWhereItem:
protected function parseWhereItem($key,$val) {
$whereStr = '';
if(is_array($val)) {
if(is_string($val[0])) {
$exp = strtolower($val[0]);
if('exp' == $exp) { // 漏洞点
$whereStr .= $key.' '.$val[1]; // 直接拼接,无过滤
}
// ... 其他条件处理
}
}
return $whereStr;
}
漏洞利用
当 $val 是数组且第一个元素为 'exp' 时,第二个元素会被直接拼接到 SQL 中,导致注入:
$map = array('username' => array('exp',"1' OR 1=1#"));
$user = $User->where($map)->find();
生成的 SQL:
SELECT * FROM user WHERE username 1' OR 1=1#
ThinkPHP 5.0 注入分析
漏洞变化
5.0 版本对 exp 表达式增加了空格限制,但引入了新的注入点:BETWEEN 条件处理。
关键代码分析
protected function parseWhereItem($key,$val) {
// ...
elseif(preg_match('/(NOTBETWEEN|NOT BETWEEN|BETWEEN)/i',$val[0])) {
$data = is_string($val[1])? explode(',',$val[1]):$val[1];
$whereStr .= $key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]);
}
// ...
}
漏洞利用
BETWEEN 正则缺少 ^$ 边界检查,且 $val[0] 未经过滤:
$map = array('id' => array("BETWEEN '1234", "abcd"));
$user = $User->where($map)->find();
生成的 SQL:
SELECT * FROM user WHERE id BETWEEN '1234 AND abcd'
ThinkPHP 5.1 安全改进
5.1 版本全面采用参数绑定机制,所有参数都会被预处理,有效防止 SQL 注入。
防御建议
- 升级框架:使用 ThinkPHP 5.1 或更高版本
- 参数绑定:使用预处理语句
$User->where('username', '=', $input)->find(); - 输入过滤:对所有用户输入进行验证和过滤
- 禁用危险方法:避免直接使用
query()或execute()执行原生 SQL - 最小权限原则:数据库用户只授予必要权限
总结
ThinkPHP 注入漏洞主要源于 SQL 拼接时的过滤不严:
- 3.2.3:
exp表达式直接拼接 - 5.0:
BETWEEN条件处理不完善 - 5.1+:全面参数绑定,安全性大幅提升
开发者应了解框架安全机制,遵循安全编码规范,及时更新框架版本,才能有效防范 SQL 注入风险。