下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。 Z1 s. h. C9 @9 r+ {) V. U( D
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件* N7 P0 \9 \1 r; y. _- C' m
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)4 ^7 A8 B6 i, _* R/ e
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:- E1 D; Y9 h! d6 p
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
9 T; ~/ ?- d+ E$ J
3 G* O+ w3 Y' }. U' K* Q1 [9 `4 N 或者2 q/ ^6 T% ^" g. [8 E6 |. C
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
% z/ _4 g3 d+ [% v) R1 m* ?+ }; {5 l( }) m3 B9 |
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
! I' x4 K L3 L8 h- ~* ~4 g$model->query('select * from user where id=%d and status=%s',$id,$status);
8 I/ d; ]) H+ k5 C& C O/ ^# J3 S7 r" p
或者* S* J) r1 R9 H6 M! N- T
$model->query('select * from user where id=%d and status=%s',array($id,$status));
+ g+ V! q+ [2 W% ^. M) ?" T& k5 }4 b. D- L- X# Z
原因:* O: y3 S) F' I9 R# C
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.5 S% E* N! d( B5 ~
原函数:
$ K( h& O: B7 t$ u1 ?" ] Z: h A9 jprotected function parseSql($sql,$parse) {% O5 ~5 j! @' b+ ~* n- v( K' K
// 分析表达式7 Y) D& _) W( ?& Q
if(true === $parse) {
" _" p- ~# \' e* f6 B' w $options = $this->_parseOptions();
5 b5 A( p0 Y& K" R- \ $sql = $this->db->parseSql($sql,$options);) t) I1 Y+ D4 A, Z2 z
}elseif(is_array($parse)){ // SQL预处理' n" g& O- \+ D8 G( [+ H
$sql = vsprintf($sql,$parse);. n) _* p; |9 a% W3 O. }
}else{
* T; x. I! c4 J9 x3 }9 @: q7 V $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
% B1 U8 b3 ]2 J }
3 Z% K( Z2 ~& G $this->db->setModel($this->name);
: m4 M! ~3 X2 Y: r* T return $sql;3 a" q# {, V/ C4 }3 M0 T0 x
}
: l4 e# i8 z# v) J
) T; i5 O3 ^- t4 K验证漏洞(举例):
) u. I0 d& d% g请求地址:3 E- B1 r: X+ Y9 ^
http://localhost/Main?id=boo” or 1=”1
* d( g3 n5 _( |) P' b7 S$ }& I3 T% a或
- ?+ P5 C0 H, v+ P- ~" w7 D# Phttp://localhost/Main?id=boo%22%20or%201=%221
3 @$ e# @- e/ W! Daction代码:/ _& w8 R- r P. ~1 A0 u
$model=M('Peipeidui');3 K5 f$ w; x/ s3 C7 g
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
7 k& x d3 b; x2 K2 |6 A dump($m);exit;* e, a% o/ P' k; A
或者
2 j" b. r, I% W; v! e! E$model=M('Peipeidui');: Y4 {; P( a& |, a4 E4 \7 V/ M
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));7 F% l1 L$ z* S7 j. C
dump($m);exit;
2 _9 J c! ^9 x: |: I结果:
, S# Y. I+ |6 M7 W r6 l表peipeidui所有数据被列出,SQL注入语句起效.
2 G1 n2 V- s4 ^解决办法:
4 Q- U) x' O8 W7 a5 d0 F. d将parseSql函数修改为:" L4 f" \* \3 z i4 y7 C7 ]
protected function parseSql($sql,$parse) {
" X9 j+ `9 M! [9 p0 H' z# K // 分析表达式
0 M2 X0 \# w5 J' r/ H if(true === $parse) {
, N a* B( Y0 s! m, @ $options = $this->_parseOptions();
0 g/ u& q8 b7 m; j- ?' T; m $sql = $this->db->parseSql($sql,$options);
9 a( A# s: F4 o% ?; G }elseif(is_array($parse)){ // SQL预处理
; v6 v3 c) i. _9 t% H% a5 w $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
) Y2 @7 v3 g* U/ n7 h0 X $sql = vsprintf($sql,$parse);: p: ?( D3 G7 @+ _7 B5 g k& _
}else{& Z- t" t) }. U* W
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
7 K. E2 o- J0 C+ d. c }
0 X% N8 k$ j! E$ d+ F: N7 l0 X0 V5 f $this->db->setModel($this->name);; [/ n* T# E! w9 `. H9 R" G1 }
return $sql;) z) b1 [% ~- B& o/ w0 {( v+ z
}
- q* D7 P0 w0 r2 J2 R4 h4 e5 x' N6 u, m3 f' H9 z7 m1 \/ f
总结:, l$ G* s" j* e
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
7 o& m; w; m4 i6 ]' S不建议直接用$_GET,$_POST
+ }- x( m$ m+ G! S% b[/td][/tr]
& O2 J2 O- Z6 U[/table]+18 x' L$ I) C8 F% E$ m
1 k+ d/ n. E$ F* u% \+ [
0 V/ x) h$ D1 u$ u' ^, K; H3 S |