下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
( p& o6 b4 K A# _8 jThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件5 a4 b% T& ^" Y5 I. r' ?2 W
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
. F. F( ?9 _* f. J _* C6 \3 Z! Q使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:* y8 g: Y9 u1 T/ h
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
4 q; c* M0 |; {* T* ^5 c0 n9 I! j# q* k8 _) p' a
或者
4 o. r% Y; ]% f& K$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();- g- w% K2 b) ~3 a' F; i+ H" L8 s
; i) ^( U# d7 q
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
# X. Y" g" z' t$model->query('select * from user where id=%d and status=%s',$id,$status);
; O# ]* ]0 X; \" I* f3 A& f& x- V O' [" P& n2 z- o# U
或者
/ N+ u+ b+ [5 m# d5 J! J7 ^; y$model->query('select * from user where id=%d and status=%s',array($id,$status));) c. c! M+ Q6 g6 r0 K+ B
+ e0 O' a7 f! ?+ S
原因:
/ [/ @3 T, }8 w1 L* I/ e/ y5 x$ CThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
: y" X: {4 M( k) \1 p, ~2 O; `" \原函数:+ e: j8 y; v" B5 [" d( N
protected function parseSql($sql,$parse) {
- \5 q& Q$ d6 H2 D // 分析表达式7 r; D3 D0 n1 s/ W, S' |9 D3 {
if(true === $parse) {
& i* J: J( m8 V1 B, k+ N6 M $options = $this->_parseOptions();
& Z+ t7 }8 y! }1 S $sql = $this->db->parseSql($sql,$options);* D( @. s8 i ?7 a4 C+ Y# B- d$ l
}elseif(is_array($parse)){ // SQL预处理
" C2 Z+ X! x$ K0 k, U( R+ O6 X $sql = vsprintf($sql,$parse);; ^6 a# X4 a) T( g9 O0 }$ b
}else{" k8 i& y, f& F) S2 V- K# e
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
0 Z7 Z( C( e0 R }+ ?9 C s5 L( j% [" Z* K3 l
$this->db->setModel($this->name);! ^; C9 {3 U- S: m- o+ z& c
return $sql;
3 r+ @" W8 l3 x/ @7 F }
! |( d2 o2 h# a3 K' A3 h4 {% y W( X6 E! R& X; q
验证漏洞(举例):! C' |# `( v2 N2 H& t6 k* `, Q/ @
请求地址:5 v) n: p$ C# e; u1 v: `# e
http://localhost/Main?id=boo” or 1=”1
& B/ L+ O& J/ P) a或) f4 g; {. A: B8 _% c% U' r
http://localhost/Main?id=boo%22%20or%201=%221% O8 _4 G' T3 Z* _& d/ I' f
action代码:
+ f; `( M \; b6 D$model=M('Peipeidui');. r* m' j% t2 p2 A- r' s7 O
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
4 j9 v* M' J9 h" d dump($m);exit;. |* `& Z& Y+ O
或者
6 v. A/ y, a5 T6 o$model=M('Peipeidui');) i* C6 E$ c/ C
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id'])); }& a$ ~# [6 q' Y! u
dump($m);exit;
3 }( G& B# X; {3 c8 n结果:
! G, O: B4 A, q+ C* H表peipeidui所有数据被列出,SQL注入语句起效.$ w2 ^4 S+ F1 G* A
解决办法:
; A& }6 p$ P3 M# e1 Z& P将parseSql函数修改为:
9 X! M! v/ W4 h. Z" Zprotected function parseSql($sql,$parse) {3 A. P0 S8 m: N$ n
// 分析表达式
( z, Q2 A' k* A0 E; q6 t- Y if(true === $parse) {
3 t1 k/ r1 p# g# m $options = $this->_parseOptions();2 Z/ m: G/ }" w- Q9 U
$sql = $this->db->parseSql($sql,$options);
2 E! n5 h/ C( a8 O4 p& d3 u }elseif(is_array($parse)){ // SQL预处理
[' i" z2 S7 R7 c$ e' ^9 c# l. V $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码3 s: Q$ P7 a# I# L# a* v
$sql = vsprintf($sql,$parse);4 z" [9 s) C7 v# I# K5 G2 J
}else{; X! y8 k; ^' c5 p
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));0 M( r! o; m% l1 D
}
0 r8 Z1 \8 F$ P! ~2 E7 l $this->db->setModel($this->name);9 b6 E5 g8 `# N1 `
return $sql;4 s7 k- m( L* d* E" [
}
2 }& Q% R" n2 z/ L( x0 Z, s4 V0 f: R& T6 }- }9 L& P5 G+ S: Z
总结:1 f* w! p. `) W6 A U3 D& p5 Y
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查" q7 ~" Q- r3 `; L& w. B! |- \
不建议直接用$_GET,$_POST
: ~! g" g$ {: W/ H' I" }[/td][/tr]
' m: a+ |, p) { q4 l3 y8 S' O[/table]+1
5 p9 {4 U/ i3 E+ G& \
) h5 ]5 X; l- q9 M! Q# b1 Y& O4 ^
% _: w$ z9 t) Y |