On the ThinkPHP official website, an announcement pointed out that the SQL injection vulnerability exists in ThinkPHP 3.1.3 and earlier versions. The vulnerability exists in the ThinkPHP/Lib/Core/Model. class. php file.
Explanation of the "SQL Injection prevention" approach (refer to the http://doc.thinkphp.cn/manual/ SQL _injection.html) according to the official documentation)
The use of query condition preprocessing can prevent SQL injection. That's right, it can be effective when the following code is used:
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
Or
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
However, when you use the following code, it does not have the effect of "preventing SQL injection" (but the official documentation says it can prevent SQL injection ):
$model->query('select * from user where id=%d and status=%s',$id,$status);
Or
$model->query('select * from user where id=%d and status=%s',array($id,$status));
Cause analysis:
The parseSql function in the ThinkPHP/Lib/Core/Model. class. php file does not implement SQL filtering.
The original function is:
Protected function parseSql ($ SQL, $ parse) {// analysis expression if (true ===$ parse) {$ options = $ this-> _ parseOptions (); $ SQL = $ this-> db-> parseSql ($ SQL, $ options);} elseif (is_array ($ parse )) {// SQL preprocessing $ SQL = vsprintf ($ SQL, $ parse);} else {$ SQL = strtr ($ SQL, array ('_ TABLE _' => $ this-> getTableName (), '_ PREFIX _' => C ('db _ prefix ')));} $ this-> db-> setModel ($ this-> name); return $ SQL ;}
Vulnerability verification (example ):
Request address:
http://localhost/Main?id=boo" or 1="1
Or
http://localhost/Main?id=boo%22%20or%201=%221
Action Code:
$model=M('Peipeidui');$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);dump($m);exit;
Or:
$model=M('Peipeidui');$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));dump($m);exit;
Result:
All data in the peipeidui table is listed, and the SQL Injection statement takes effect.
Solution:
You can modify the parseSql function:
Protected function parseSql ($ SQL, $ parse) {// analysis expression if (true ===$ parse) {$ options = $ this-> _ parseOptions (); $ SQL = $ this-> db-> parseSql ($ SQL, $ options);} elseif (is_array ($ parse )) {// SQL preprocessing $ parse = array_map (array ($ this-> db, 'escapestring'), $ parse ); // code $ SQL = vsprintf ($ SQL, $ parse) added for this behavior;} else {$ SQL = strtr ($ SQL, array ('_ TABLE _' => $ this-> getTableName (), '_ PREFIX _' => C ('db _ prefix ')));} $ this-> db-> setModel ($ this-> name); return $ SQL ;}
Summary:
1. Do not rely too much on the underlying SQL filter of TP. programmers should perform security checks.
2. It is not recommended to use $ _ GET, $ _ POST directly.