下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。$ J% s- R) D2 k; L6 v
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
; r" f* l f0 y W( h2 r根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
5 t! ^4 X7 T; v使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:# [8 c3 e. {% t9 V9 P, q& l3 M
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();( |% T0 e2 G8 N# p
0 j J7 X# Z1 p& O 或者$ q U/ R& V" o
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
5 `4 i" p9 H4 i) D) E
9 o, u0 w' q& C4 U8 `9 _5 K R 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
, [) |7 R; _- D% j4 q# f y$model->query('select * from user where id=%d and status=%s',$id,$status);$ G7 k" L! b% s. I! s3 C
) `# j) S) C; Y( k
或者0 }+ x, D* u+ a$ q' s$ G; V' }
$model->query('select * from user where id=%d and status=%s',array($id,$status));
# ^% j# ]8 w% }. H0 w2 A) K* ~7 d4 F
原因:
2 S% X. d( q1 X) N" D- K2 S' kThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.# E. l e7 ~% O2 i7 u, M# z, \0 l: X
原函数:
$ S5 p2 T/ c" J$ r! Y6 a" U) \protected function parseSql($sql,$parse) {3 U6 ]. l% \2 m% n) A! c
// 分析表达式- X1 L- ^- U* d9 a
if(true === $parse) {) x" E# s6 e2 D- j; j. d7 C3 X
$options = $this->_parseOptions();
1 Q1 n% a# R0 D0 y, L6 R, n $sql = $this->db->parseSql($sql,$options);' b. U; @: Z2 |! G4 D0 k4 C7 Z
}elseif(is_array($parse)){ // SQL预处理' j2 m8 a4 ?1 r
$sql = vsprintf($sql,$parse);
4 @1 u- d+ R) f. o7 q }else{
3 w: C2 Q' X8 z- u $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));* y" U4 y# d6 I' H$ o
}/ g# x) n( x/ Y$ L, T
$this->db->setModel($this->name);
" ^! {6 V4 \# R" V) ?( X% z return $sql;
, t: ~2 W! a/ }( j/ r }
2 c o! f8 I9 V& T
8 T& k1 v2 @. b# w3 |. e1 ^验证漏洞(举例):0 S4 ~" U8 ?2 E; ^/ F% j
请求地址:" o) H! M- l$ {
http://localhost/Main?id=boo” or 1=”1# _1 s- a8 }5 T- b
或
0 B) N- Z6 a8 d9 b1 J% Rhttp://localhost/Main?id=boo%22%20or%201=%221
) N- U' v) g, a" Z; I/ F1 a Daction代码:' } Z3 h; a5 @8 V# v
$model=M('Peipeidui');
) y8 E! u/ n. J' W $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);' _6 i+ C5 e$ ?) e: H d
dump($m);exit;: k) Z4 U! J: {# t% E3 `" |
或者
- k, J$ l. I7 T' t/ a$model=M('Peipeidui');
) o9 {% Q$ ?! T' {1 a# I1 E $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
# }" e( U0 c/ B3 t dump($m);exit;
7 |% w7 P) Q! B3 y! D1 T& Z结果:0 q. R9 ]5 }; S1 \7 W
表peipeidui所有数据被列出,SQL注入语句起效.7 R8 a. L# [5 n0 D* ?
解决办法:
! i8 X; s5 X. H$ e; y将parseSql函数修改为:
. h/ V' w% T& E& {protected function parseSql($sql,$parse) {- g) s9 S( y) Q( z. ~6 ?/ e: P
// 分析表达式! o9 m5 m% X3 G9 G+ `$ u& e, p
if(true === $parse) {
" \0 S7 @" c& V# P $options = $this->_parseOptions();2 S" h! w8 `/ [# g. }
$sql = $this->db->parseSql($sql,$options);
3 P2 W5 r" v1 [ }, X }elseif(is_array($parse)){ // SQL预处理
/ ^6 x/ U i' a! H, B' B $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码' B, o' u! F# q5 i. C2 z
$sql = vsprintf($sql,$parse);
$ ]0 P' Q7 {- D }else{
5 m6 y2 e* m9 N( @ $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));7 ~; h+ `% t; z. C3 z. L. u5 _* p
}
' v# t4 _: u( o0 d $this->db->setModel($this->name);& C4 L5 M5 u1 G5 b7 E7 h/ s
return $sql;" J+ l. Z/ Q) `. Q5 S
}3 d! `; n; y. I. @3 o( I1 d
7 U- N- [, z, Y h总结:
' v0 y% n n3 P# U; A& r不要过分依赖TP的底层SQL过滤,程序员要做好安全检查- K7 \0 A8 s+ P" y3 P
不建议直接用$_GET,$_POST
' ?2 _% u4 U2 V. b% n[/td][/tr]) V2 g2 \9 |0 d
[/table]+1
4 z1 a j0 T% o" ]" d& T5 F6 y' J4 z& u0 U0 }
6 N; ^9 S# I/ p |