下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
3 F1 Z* K- b/ f: _ ?7 V% vThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
2 w; \! J4 D/ r1 A6 {( D8 r根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)5 z8 V- j0 N5 ?: G; b2 w3 } S9 {, b
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
' e1 a, R& k) o# ?$ d$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
9 o- K6 ]2 ^! k4 k9 j6 M7 v! n2 Y5 \! `* _4 |* e- ~
或者! s6 B- V( E3 Y6 S+ z# P* Y( c
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();) Z+ Z; }- T: V$ |1 M
" B3 b5 D' F# ^. b
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
- w' T; `; S$ q: V: b$model->query('select * from user where id=%d and status=%s',$id,$status); ?$ F8 H+ }9 X+ k* b
& q9 B9 d9 N( J0 o2 R或者. c; ~: a% O% g+ |, @( q
$model->query('select * from user where id=%d and status=%s',array($id,$status));$ e1 X, X$ {% A5 t' O. x8 N
8 ?( k5 [# K% }" p- r) l6 f 原因:
- z3 K& u- y3 W0 }" yThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
3 L% A, E3 X5 f) G! x原函数:. f/ b5 ?" ]5 F
protected function parseSql($sql,$parse) {
9 c A3 P+ N9 R( [* J // 分析表达式
" Y' G' h+ I; c if(true === $parse) {% v$ g" ]" a/ F& j5 b1 d: {
$options = $this->_parseOptions();
7 e4 m$ _% J( n" r5 y% [) e. y $sql = $this->db->parseSql($sql,$options);4 ]3 G1 V/ t! k, {0 E* j2 e
}elseif(is_array($parse)){ // SQL预处理
# D& B6 N* D8 b: Z $sql = vsprintf($sql,$parse);2 V9 w$ n4 k. S! ]5 k. P# z1 a
}else{
: K6 \8 B- u( f* W( ^ $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));6 W3 q; [8 r0 V$ w+ S
}+ [8 g- U. b2 w9 s/ D% M3 z0 \
$this->db->setModel($this->name);
- f- k; ]- X) \/ D8 ^' ]! l return $sql;
0 l: d, u2 V0 q3 e: D7 v1 c }* ]/ L9 F$ E6 W- X7 G1 M0 @
% V/ z) j8 B; b; E
验证漏洞(举例):: r b- |5 F' O8 C/ O, J2 l- H
请求地址:+ t; c$ c2 l5 X( ~. r) V
http://localhost/Main?id=boo” or 1=”1: X6 o8 ?+ @% p6 K7 S: O
或- Y& d) K: {; l1 b) S% T& j
http://localhost/Main?id=boo%22%20or%201=%221/ |9 r% @# a- T: {3 r! c9 N! G
action代码:) o$ [2 E$ v3 Y# \/ t& X+ ~
$model=M('Peipeidui');
# ]2 C. a& j, y. x* N- M0 U* @, b $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
5 q4 h F$ W. w, Y dump($m);exit;# [3 A' C5 s# q& c: \5 H
或者+ d! x6 B% z% p8 g* l+ I2 ^- h
$model=M('Peipeidui');$ {, ~4 J% C* C0 n% d4 p& t) B
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
4 C. s4 H; Y; q" `* X& T) D dump($m);exit;
, S6 Z& q- [% g- T* m$ b结果:
8 A3 }3 g3 V0 a+ D表peipeidui所有数据被列出,SQL注入语句起效.+ h* F4 l# w: l6 u( |
解决办法:
! n: t5 }% H' d将parseSql函数修改为:
% I1 k1 E/ A {% x1 M) A& |7 k& |protected function parseSql($sql,$parse) {1 v# x3 C2 b" A+ \4 V" y, ~
// 分析表达式
k0 {9 w0 N% g6 w1 i0 a if(true === $parse) { \* ~& j: n: B6 E9 O! L" s
$options = $this->_parseOptions();$ U: c+ r4 u1 x: ^$ a2 [
$sql = $this->db->parseSql($sql,$options);
! K. R! A) s+ h q3 w' t/ P }elseif(is_array($parse)){ // SQL预处理. G3 ]. x5 c1 U, ]' R) I- \
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
3 g* D9 I: ]% |5 C, w $sql = vsprintf($sql,$parse);
6 ] ~2 a9 d. Y+ A4 i) j }else{
i/ O# a) N" _% |' f $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));; X. h% z, a0 b6 e9 [
}3 h4 y# `5 E) R8 L. P$ q
$this->db->setModel($this->name);
4 A9 W2 d& F# ~+ B, O return $sql;
3 F0 r# O# G |4 o: m" { }
# U/ w- x- B+ s+ a) W1 |; b- a9 o: k% N+ Z% u) W$ \% N
总结:. ^; o3 V( D( `9 G3 k3 B. Z! ?- |) b+ T
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查. Q' k% n6 b) x! S7 v5 H9 F
不建议直接用$_GET,$_POST5 I7 f8 O" g# ^' e1 W
[/td][/tr]
8 p4 i, \* _$ V( G. D9 P! G1 z[/table]+1
8 j8 b D# b p+ \, L$ i! V9 r4 m# U& U
# i k9 j1 T: J, o% _ |