下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
; I8 e7 U: ]% F4 d, S1 G7 ?ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
: h. e' d, t3 }* D3 u3 f根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
2 x0 h9 R# u$ c& x- a% ~4 _使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
9 w6 @5 I& b; W0 _$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
/ \' b/ O" d+ c6 o. k1 C6 d; O* ~ y
1 |9 e: l% e+ b* Q' `$ O$ E 或者) A6 D$ L. C+ A) r/ m9 ~) n( |
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();1 X }+ [% O& @* O
: J% W+ w& R( g4 F+ x 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):* m7 u8 M |* u. L2 o5 w
$model->query('select * from user where id=%d and status=%s',$id,$status);
! n. x- c% g' i7 ? z3 p: n; |, C7 O# h$ d- @( x# m w+ x
或者# p9 u( [8 ?2 I
$model->query('select * from user where id=%d and status=%s',array($id,$status)); J( J, I. g, k
" h o) g3 |( V4 k8 \: B7 V
原因:( `; S q4 k& H( Y/ Y. r
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.7 Z$ z3 @( }& s% Q c1 ^ y! X% G
原函数:+ I2 r" _, b1 C. {6 K% g( [( `% @( z
protected function parseSql($sql,$parse) {% C" j8 h( ^6 K" a# @* b( h" j5 U" k
// 分析表达式
8 h! ~9 u5 O2 m8 Y: r2 Q if(true === $parse) {* n. v( Y f7 h ]# r; R
$options = $this->_parseOptions();+ b b5 q2 q1 z; `
$sql = $this->db->parseSql($sql,$options);
8 M$ ]4 T b* Y9 ]! D( M! z# q }elseif(is_array($parse)){ // SQL预处理, l# @! J. `5 b, F$ L V2 _
$sql = vsprintf($sql,$parse);2 G! g3 H9 a/ g* x0 v4 t+ q
}else{
7 z K2 B. o T/ Z; a& |' a $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));8 d0 D- e% I8 J, `1 C) U/ @/ n1 K
}9 a. f7 p5 ]: r; Y( Z
$this->db->setModel($this->name);
6 Y) Q% m! a( @, b6 p4 V+ {# f/ y return $sql;# n% ]! [ \. B9 X3 x7 z9 @% g4 i
}! m$ l5 h( L: `& N; I2 G+ Z
- v" e6 u4 b/ o$ Q- k% S验证漏洞(举例):5 v) V# ~: ~$ v* _+ ~' u0 A
请求地址:
4 E" l! d& x- ^" {; G( K! k jhttp://localhost/Main?id=boo” or 1=”1/ {& _# j( c# V& L, m0 n- G
或) z4 e+ m. V, {
http://localhost/Main?id=boo%22%20or%201=%221
' J3 f% A1 W) |3 p( w! C7 xaction代码:
* c0 l* S9 G" d/ s. g$model=M('Peipeidui');% }- j/ v: { I1 {- X2 }7 l
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);1 ]4 @* ?0 E% b/ Z
dump($m);exit;" M* ?5 f7 I; K }* e# C0 ~
或者! `6 O* D! M4 {7 ]! B8 W
$model=M('Peipeidui');
( _+ |. @) g2 L3 A $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
0 E6 @. ]8 i; ^7 X5 Q1 q dump($m);exit;
2 |3 y; u8 M! [$ y% C结果:: X: H q$ S- b4 ]1 e. o
表peipeidui所有数据被列出,SQL注入语句起效.9 I* D6 {1 D1 ]. S; |, n8 X/ b2 G
解决办法:) K1 U: [, X) }
将parseSql函数修改为:. y/ I! M% }7 j' C
protected function parseSql($sql,$parse) {% m& e- V, C& `/ j
// 分析表达式
6 T) L0 F/ D. | if(true === $parse) {7 H; I& X" v( G3 D$ u
$options = $this->_parseOptions();
6 \" E7 \$ X, a1 S6 ~9 m $sql = $this->db->parseSql($sql,$options);
6 a; H( m( |9 }3 U }elseif(is_array($parse)){ // SQL预处理
- K' J3 r: v6 g M8 W' v r# @ @ $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
: z3 W, S* h2 p1 T1 }6 C $sql = vsprintf($sql,$parse);
6 v* m; O! e; v }else{) A+ d1 v( ^9 O. o' j4 @6 Y
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
( s. x* T. {0 S9 q! ^2 k: p8 O }
+ Q5 E) B) s; M0 K0 j: t- N/ e $this->db->setModel($this->name);+ o# g# ^/ Z3 t# x8 Y, A* Y9 M4 a; d
return $sql;9 I( \( ]9 L% h- D& n6 F+ Q7 s1 H; m
}% A9 x$ o! H5 Q0 X8 e5 k
, i% S; K% p7 X6 `( H2 u2 R
总结:! h: I0 d4 R1 { I8 U
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
" Z1 t e9 w# \# L3 M* _) e# A3 F不建议直接用$_GET,$_POST
/ m' ?. N, V' D6 f[/td][/tr]1 T0 x+ D5 _ t* S- x. a+ X( J
[/table]+1/ @! W8 a7 T& J7 e
2 c7 ]' J! d" Q& t& I" f6 s8 T
7 ~2 f9 ~3 c; b& k1 ?
|