下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
( u v( S3 \# g; j# F& }5 bThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件 Q0 v, Y- M! l
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)2 B h# S$ M# L' `- r }/ I
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:+ D' P' u A1 w
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();/ J7 L6 u3 U \2 v6 X
# D. }$ y/ E0 r7 A' e 或者, X% G, j1 w! ^
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();' X8 c4 F, _2 Y# X
- j! P& N( x1 T: ? 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
0 T. K5 K$ b' {0 l' B$model->query('select * from user where id=%d and status=%s',$id,$status);
" j! N* K1 P* @- q/ o+ x1 J( }
# m# L/ t% [4 v9 P, Z4 T/ }或者
) m4 C9 M) Z8 g6 d$model->query('select * from user where id=%d and status=%s',array($id,$status));1 g( ]7 W% p: i- }, E, Z
% A9 ^6 p+ N S 原因:
! j+ i( y4 b9 Q# [& H/ E! NThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
7 ?/ \$ `. t2 K8 [* d- `5 A/ G4 v原函数:* N7 C6 V% e8 {1 J/ s2 e! K7 R/ ^% w
protected function parseSql($sql,$parse) {
8 [. ^' ` w% ^2 U // 分析表达式
, J# L8 u; D2 W if(true === $parse) {
. P$ \' ?$ q( m7 U$ i* o' m; w, r $options = $this->_parseOptions();
0 M! o5 T/ c+ ^) i6 [3 i, P' c n: W $sql = $this->db->parseSql($sql,$options);
; X3 l% T: H9 S: { ], G7 i7 ^ }elseif(is_array($parse)){ // SQL预处理
* W9 x9 ?7 ?: R $sql = vsprintf($sql,$parse);
# ^1 o9 `6 o' B: Y) k }else{
4 A- p2 d0 v; q) I" ? $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));6 [1 z* e# f. N* N
}
+ q- O4 i3 e; k [( P# x2 o* v $this->db->setModel($this->name);
& w. H" Y% e; [: a7 o( ~" a9 | return $sql; o3 u8 B( @; F
}
2 F. h9 _9 q" t) B$ m7 q5 r# d0 ]: I n/ Z
验证漏洞(举例):. J v& S+ N3 p8 u0 I, _0 P
请求地址:3 g& V! v" I: v
http://localhost/Main?id=boo” or 1=”1
9 Q n: }& U' t3 {或
; I7 d! i+ D3 i% [1 N0 Ghttp://localhost/Main?id=boo%22%20or%201=%221
4 Y t X0 l4 E0 S" F J5 P$ @: Gaction代码:
" M6 h% _" T1 F( d, ~$model=M('Peipeidui');4 w8 m E" H2 R" @, L
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);4 G$ c C+ g8 f5 y
dump($m);exit;
# {; s( @ A- s6 K5 w. D或者: N/ B/ v# ?" W, q7 N8 K; H
$model=M('Peipeidui');
/ V+ c; c- K6 H. s! D3 w- K $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
1 R7 N& ^' o. p+ m dump($m);exit;4 S; z3 L8 j8 H
结果:
4 ~' }2 o |; W表peipeidui所有数据被列出,SQL注入语句起效.
, w) [7 @4 Q2 j: o解决办法:
8 |. y7 s5 g9 y) m8 N将parseSql函数修改为:
K# q! A- z( c" r0 ] Zprotected function parseSql($sql,$parse) {' M% \# A5 b9 B9 u/ r* h
// 分析表达式- u) Y* I" Z* G: o3 J& ]6 _
if(true === $parse) {+ ?& M( i+ L3 r6 V+ d
$options = $this->_parseOptions();: I* J2 Z X8 C w( m
$sql = $this->db->parseSql($sql,$options);- ~1 ]1 c; r' Z/ q6 X
}elseif(is_array($parse)){ // SQL预处理) D. g' w! s5 H3 F4 U
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码7 ]0 H c- Z* ?2 z" e& W" B# |
$sql = vsprintf($sql,$parse);
t0 C" k! N& z7 t4 P8 X& P }else{" K2 Z* c- E% L. a J
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));' M1 G! Y0 g E( f# K
}/ K, j, d$ _7 w1 B- R1 r
$this->db->setModel($this->name);
! G1 C' X# V5 f/ p9 N return $sql;, s: [& r% Z, }/ j2 X
}
r; P3 z* J' W3 j8 A) Q+ T9 [4 _- G1 L" e% E6 D- K l& @
总结:
) F. U; Y7 R8 V9 p# w2 \) g2 _不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
6 x' i: ~: r; Y- q H# W9 m不建议直接用$_GET,$_POST
$ R: `9 n* g7 R[/td][/tr]1 v2 g; U, D1 v; e6 N, [, y6 ^% c
[/table]+11 h6 Q) J) D) b- E- P* N# \! d
- H5 }. y& g9 J
5 Z3 s9 D$ d& Q2 F |