下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
2 u( E2 \- a3 {ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件# f3 p( m1 O" E% _
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
}( ~) g7 C9 r6 @& ^1 S+ M使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:: X: z' p: K1 |! A
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();3 c0 A6 Y, S2 n+ \$ f0 w
, J* ^5 Q7 L) R# I/ y1 Q3 |6 {
或者
6 ?. c5 `1 F5 C! L* R# G$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
4 b" P- V! `5 @2 E' i0 |' W) D4 N$ E; Y7 R% q
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
7 l& q2 F* I# g' G5 H/ ~" Z- [8 C$ y$model->query('select * from user where id=%d and status=%s',$id,$status);6 A) K+ U4 O1 [" _3 x
7 C3 \8 z$ x: H4 }7 h; @9 t
或者$ g3 ^1 K& \; v& T( t3 R
$model->query('select * from user where id=%d and status=%s',array($id,$status));( a9 y9 @4 s3 z3 b& @
* C" T. q; K& z$ L1 q# C4 ?% \ 原因:' m7 `; B. t) n; C8 {" h
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
+ z, d+ ?( i `" r, J* u* o0 r原函数:
W/ N& I* j L/ a# i- z7 Vprotected function parseSql($sql,$parse) {, h) y4 @% t1 `# s) r. {# t7 L
// 分析表达式
- A" B: L0 S! j) k0 t if(true === $parse) {& w0 d4 A- ?. f9 A N
$options = $this->_parseOptions();/ m4 g6 C, L I- p
$sql = $this->db->parseSql($sql,$options);, p9 `8 s% w0 j2 W- ?$ ~; z; }( B; r
}elseif(is_array($parse)){ // SQL预处理
6 D) p0 `9 i( `8 r3 I' c $sql = vsprintf($sql,$parse);
" i+ g9 l7 @/ R( I* ` }else{
$ u4 C) L- L [- A9 l2 ~7 w5 {& ] $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
8 X$ y, ^- b5 ~! V3 g, Q }3 [# G9 m( H" U+ O
$this->db->setModel($this->name);
# Q( G! P3 `; B& k; U return $sql;
7 c2 w9 B% r* z8 S( @ }
/ h/ J6 A ]: a7 Q! x
7 B6 w: d7 P$ Z6 V4 D; F验证漏洞(举例):
@, b/ n& h, O0 S请求地址:
" U; h: X c# V" zhttp://localhost/Main?id=boo” or 1=”1$ ?: o5 i$ _. E( i% S
或, m, c# ~0 Q' N
http://localhost/Main?id=boo%22%20or%201=%221' l/ A7 O& s$ N" V d" L
action代码:
2 ~8 ~% Y8 `( O% V4 J$model=M('Peipeidui');
1 y0 T2 ?: W+ y P $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);1 R; N& ^/ F% y/ f+ i1 h
dump($m);exit;
0 c& M2 C: l3 e! f或者+ e& v7 l3 A) M4 B' t* P* O
$model=M('Peipeidui');
8 i5 t# g' V6 s2 n0 I $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
$ R' v7 u( [2 }7 S* |' e dump($m);exit;! D8 P# i8 |+ j" p3 G: R
结果:: H1 V( s$ I7 q* g& p" T! V' G
表peipeidui所有数据被列出,SQL注入语句起效.
( q1 [# e' v1 a9 e$ ^解决办法:
3 r7 R5 e' \( z% C, ^将parseSql函数修改为:' \+ {% q% x& `4 ] c; E& v
protected function parseSql($sql,$parse) {
\+ g. ?0 M) n- B // 分析表达式
- E- \9 m; m7 s3 k" H- Z# @3 e0 t if(true === $parse) {# Q9 E0 r+ L1 _7 |
$options = $this->_parseOptions(); s- o- U8 y. N. l7 j m( w
$sql = $this->db->parseSql($sql,$options);6 m+ h/ \1 {) z) s
}elseif(is_array($parse)){ // SQL预处理. W; f- [* ~4 T+ n0 o$ u
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
9 o3 a' k' O: I- @ $sql = vsprintf($sql,$parse);* i; V9 x7 f) O w7 [) i' H- P
}else{ \7 C7 t9 S* N K" p
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
' Q; L# x+ }/ l" Y }
2 U% C- I- X7 B) ]5 W# D* ^ $this->db->setModel($this->name);+ C* R5 Y4 t: {# [$ g; R& a9 v
return $sql;
- ~9 f8 z& W/ Q7 {" l+ b f- k }1 A1 r. R3 L7 I
+ ?* ^3 @. u# |5 m
总结:3 x l. `/ _* x* A; d2 z
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查, P, l6 ?9 i2 h( Q
不建议直接用$_GET,$_POST$ q, Z c$ e$ k0 a$ ^3 B$ n
[/td][/tr]
. M5 p7 \% h- Z. ?! r8 Z- ^6 c[/table]+1
5 j' E; ?7 }& G- M
) n- t( _. l& \) R! {* [2 A! c ^& b5 T$ }! l
|