ThinkPHP官网上曾有一段公告指出,在ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
根据官方文档对"防止SQL注入"的方法解释(参考http://doc.thinkphp.cn/manual/sql_injection.html)
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
1
|
$Model ->where( "id=%d and username='%s' and xx='%f'" , array ( $id , $username , $xx ))->select(); |
或者
1
|
$Model ->where( "id=%d and username='%s' and xx='%f'" , $id , $username , $xx )->select(); |
但是,当你使用如下代码时,却没有"防止SQL注入"的效果(但是官方文档却说可以防止SQL注入):
1
|
$model ->query( 'select * from user where id=%d and status=%s' , $id , $status ); |
或者
1
|
$model ->query( 'select * from user where id=%d and status=%s' , array ( $id , $status )); |
原因分析:
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
其原函数为:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
protected function parseSql( $sql , $parse ) { // 分析表达式 if (true === $parse ) { $options = $this ->_parseOptions(); $sql = $this ->db->parseSql( $sql , $options ); } elseif ( is_array ( $parse )){ // SQL预处理 $sql = vsprintf( $sql , $parse ); } else { $sql = strtr ( $sql , array ( '__TABLE__' => $this ->getTableName(), '__PREFIX__' =>C( 'DB_PREFIX' ))); } $this ->db->setModel( $this ->name); return $sql ; } |
验证漏洞(举例):
请求地址:
1
|
http://localhost/Main?id=boo" or 1="1 |
或
action代码:
1
2
3
|
$model =M( 'Peipeidui' ); $m = $model ->query( 'select * from peipeidui where name="%s"' , $_GET [ 'id' ]); dump( $m ); exit ; |
或者:
1
2
3
|
$model =M( 'Peipeidui' ); $m = $model ->query( 'select * from peipeidui where name="%s"' , array ( $_GET [ 'id' ])); dump( $m ); exit ; |
结果:
表peipeidui所有数据被列出,SQL注入语句起效.
解决方法:
可将parseSql函数修改为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
protected function parseSql( $sql , $parse ) { // 分析表达式 if (true === $parse ) { $options = $this ->_parseOptions(); $sql = $this ->db->parseSql( $sql , $options ); } elseif ( is_array ( $parse )){ // SQL预处理 $parse = array_map ( array ( $this ->db, 'escapeString' ), $parse ); //此行为新增代码 $sql = vsprintf( $sql , $parse ); } else { $sql = strtr ( $sql , array ( '__TABLE__' => $this ->getTableName(), '__PREFIX__' =>C( 'DB_PREFIX' ))); } $this ->db->setModel( $this ->name); return $sql ; } |
总结:
1.不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
2.不建议直接用$_GET,$_POST