下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。+ Q. T* g0 P$ b( u; t" P; e
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
! l7 `/ u% F9 a; h+ W$ N根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
& n* A5 A4 e1 t* v1 {使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
1 ]- B& \- V- n9 Q) Q$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();7 |" a/ P; \. ~" m9 T! q
1 r/ I5 J+ O1 e
或者4 R2 W; T0 H5 M( o
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();, O2 H( ] ]: ?/ W
3 E" F8 H/ L9 x# Z0 l 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
# _ P4 j! t% U3 q1 I: d4 `* ~$model->query('select * from user where id=%d and status=%s',$id,$status);) P6 u# Y7 ~! u+ o8 I) {5 V
! E. V; D; o' \7 e) O或者
1 c& O; P' b- F/ N5 T6 p+ z$model->query('select * from user where id=%d and status=%s',array($id,$status));
' {0 O% G0 I+ k# Z+ O0 ]( W1 F u! r. H
{1 i+ ^* V0 L+ j 原因:4 m% M8 c+ u `- U$ A: X _
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.* m' z. N, c. D
原函数:/ B- F; |3 Z+ g" Y0 z I. ^
protected function parseSql($sql,$parse) {3 C5 n' { ~: A; ^2 Y
// 分析表达式
$ \# e4 k# e# A if(true === $parse) {
4 b6 _( d5 t$ p) d, w6 e $options = $this->_parseOptions();+ w/ M1 {8 d: H
$sql = $this->db->parseSql($sql,$options);5 G2 v& P7 F% K2 B1 K, Q8 d
}elseif(is_array($parse)){ // SQL预处理
. }1 n. o# L- d; R2 X6 }- w+ D4 r# i $sql = vsprintf($sql,$parse);* ~7 B0 [$ p; k$ j
}else{* t# e2 m# q5 J7 [+ W$ m0 @& K3 Z
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
6 ~# X5 ?- s; b7 O7 I, ~ }
, ^3 V( g7 K- c$ K $this->db->setModel($this->name);+ `8 ?7 ?$ v- |3 v8 ]" y7 T6 M
return $sql;
8 s0 C1 o0 k( ^! n% k9 z }
& G; Z9 x9 n. E1 q) F, h
" P& i* m# h2 c1 r( L/ y验证漏洞(举例):1 W2 @- Y3 {% A% t7 M; p
请求地址:
2 _) U, x& O% Rhttp://localhost/Main?id=boo” or 1=”1& G* ?. d2 V! ?* d
或
7 r7 C, [4 L8 `9 y3 Nhttp://localhost/Main?id=boo%22%20or%201=%221" G7 m8 B! m: c* B: d3 H# c; `
action代码:: L7 K* n. i( H: T& U) \
$model=M('Peipeidui');
1 u" D5 E3 F/ l7 E $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);" E+ L6 }/ ?9 A
dump($m);exit;" e" h7 T& M4 o9 q$ l: c
或者
9 i8 J" r" x7 @$model=M('Peipeidui');
. W+ r5 r1 W3 {* _: b' V1 k$ ?3 K0 l8 C $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));, S& B4 n6 ?/ ]% Q0 r
dump($m);exit;
5 G* \- X1 d/ {, X结果:3 ?- G" ~1 A: a* {. i
表peipeidui所有数据被列出,SQL注入语句起效.
! C+ @) M3 u5 S解决办法:! P _/ K( P' L3 v) f" x
将parseSql函数修改为:- V9 U+ `* t) n. ~
protected function parseSql($sql,$parse) {
4 @1 ~+ X4 P6 b$ { // 分析表达式2 ^$ R0 ]0 W) @# m) ]
if(true === $parse) {: B. p: K" [7 i% l3 U* F2 m
$options = $this->_parseOptions();
; x* e& ?* @! {5 x) O& {0 N $sql = $this->db->parseSql($sql,$options);
9 [8 m9 i! Y% S6 I% z3 ?2 y }elseif(is_array($parse)){ // SQL预处理, P& s" i; {, o" W
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码" g. g9 Z; n! r) m y# ?( A
$sql = vsprintf($sql,$parse);3 m) z( G* u Y! Q) m* B. }
}else{) \; Y: i, I/ I; f# G1 K, ^5 l
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));- n5 s O; j& v l& B
}" g4 T5 g1 o! k; o. R" o9 T1 H0 U
$this->db->setModel($this->name);2 U% L* u0 O+ E& J, G+ T
return $sql;# t0 [) P5 t" j* H: c
}7 Y7 S8 g8 q. o |8 C
: N; @% c1 @- x" V7 Y; x& L
总结:% B* g, K) j6 d N
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查5 t5 U4 H/ N* t4 f
不建议直接用$_GET,$_POST
5 _ l D5 J% x- t[/td][/tr]
7 ~; d; Z; e7 \[/table]+15 h i2 X- a/ g. X+ u5 K
( T8 ^6 G6 k# r% w& F: K! Y
/ k& N) M) i0 L |