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