下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。+ q; U" ?. d# K& |0 Q" d: Q/ m& w
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件$ A3 X [1 t2 C. S) c9 N" P1 o$ j
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)2 w( R. ^. G$ L% a/ ]2 V: y
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:. n: L% N7 @) U7 Z3 ~4 l
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
4 }# j% ^1 F: ^) I* E) t( F, @+ v' t9 h/ [, |& X
或者% w8 k5 a. h0 b. m4 f" d3 y9 z D: R
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
3 U- U: J' ^3 a E) j: C: I; z1 H, |& \, u
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
9 J- M* S, ?) H8 B$model->query('select * from user where id=%d and status=%s',$id,$status);
( u. e8 x9 g2 r8 {, |. m% j, C0 Y! d ^+ o) t1 S! l
或者" P/ y |( w3 U, C+ d! x' ? I C0 n/ o
$model->query('select * from user where id=%d and status=%s',array($id,$status));
" K+ h& |- R4 y; g9 T/ Z% c% O7 H0 \8 y1 y
原因:
2 j1 P7 d& M: q3 s U, u CThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.2 K+ G) a' g* F7 U) f
原函数:0 E% [$ d& e4 z6 |
protected function parseSql($sql,$parse) {
: q$ W2 d# N7 H+ p6 ^ // 分析表达式
9 ~% C; }. W# B( p9 j- Z$ q if(true === $parse) {
d8 v+ K5 V; @ $options = $this->_parseOptions();" H( b( `/ V! u# R3 G
$sql = $this->db->parseSql($sql,$options);5 i: t, W( X: o8 b- e9 K2 ~
}elseif(is_array($parse)){ // SQL预处理# y; ^ U9 C2 a
$sql = vsprintf($sql,$parse);7 t( ] E1 h) S* v* Z/ ` c7 N% j
}else{* x K3 G s' W; f" C$ K4 f% N
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));9 j I# P7 b5 I8 l
}+ G, s3 w7 j ?* c- J
$this->db->setModel($this->name);* u5 }! `! D' ~/ z( j) b! T
return $sql;
7 A4 C9 ?, E& a- z+ S7 B" o' k% P }
7 q \# ]* \! F/ e I" [7 p- N$ I0 K! V0 o
验证漏洞(举例):
2 h4 h8 d: R- j- Z$ J L" O请求地址:8 q5 b% O3 }. \ y% l
http://localhost/Main?id=boo” or 1=”1& y2 {) N, Y7 p' k. }( \8 j$ a0 g
或
! G9 v( Q8 N" {" A+ Zhttp://localhost/Main?id=boo%22%20or%201=%221. z& B5 f$ h3 y
action代码:
: M" s4 G0 \1 y% x( N1 ^6 j$model=M('Peipeidui');0 c. V3 f6 v R0 ?- a! O0 [
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);# `. K: A- g# Z3 Z& ~( T& v
dump($m);exit;* w, d) y) V7 v6 _
或者
: Q2 Z4 O# K r4 h$model=M('Peipeidui');
* l- N+ q' b* o8 v5 Y8 P $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
% ]6 f% D3 R* J8 F+ {% I dump($m);exit;
: _3 I8 n4 [" h/ |结果:- M2 P- A5 H: g; g4 \0 d5 E
表peipeidui所有数据被列出,SQL注入语句起效.
2 b2 G; Z( |% j解决办法:) F' Z1 A( j& F* i, Y4 v9 [5 r
将parseSql函数修改为:' R# b! T9 o9 {0 z* u* e4 A9 r
protected function parseSql($sql,$parse) {
: J8 N% O) M; K6 b x% N, Y, \; p // 分析表达式
0 p; D9 a2 {3 N- U* R, f* c# u) a2 c! E if(true === $parse) {( g6 V' ^0 v2 ]; I% O
$options = $this->_parseOptions();; d; d: d/ X4 H v" y$ q* o
$sql = $this->db->parseSql($sql,$options);+ R- z+ z* ?) b1 _0 Q
}elseif(is_array($parse)){ // SQL预处理 T; ]9 b% Q x+ D/ j& ~! t# ?
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
+ w( D+ ?% B/ Y- a& ~ $sql = vsprintf($sql,$parse);$ C+ @/ G& l X9 |0 R
}else{; T( t0 ~5 J( I! s( M
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
3 H) e$ j3 n5 k8 Q }
0 c& L1 l( ~1 { $this->db->setModel($this->name);5 k* W$ D) Q: i, L7 ~" [3 o; H5 e
return $sql;
4 N8 N* V9 s7 D+ a% ?, X$ q, v }9 v( h& k' s, m# @- F9 O M5 z
) B2 q, m% n1 K2 M4 }* i# ?0 L总结:9 q4 L: R1 S' Z% j# W. Q
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
% k. l) H0 F; u) C. c! F不建议直接用$_GET,$_POST
* w5 `! N8 A9 x( t* {( c' Y8 s( B- y5 X[/td][/tr]
& X3 W% Q& Z) w% a3 g0 e+ k[/table]+13 F9 c: J9 j) I# S! j) I
: F. B! M5 e6 c% C7 O" [; h
1 c& \; X( \: m$ @0 r |