下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。' c( P4 p' @0 m& i; K# c
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
( R3 b; u3 Q! s& X/ Z4 [, N1 f根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
. K* d" G; }: U. w7 ^) U) Q使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:# ]7 D" R% O9 z, J
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
! @; w; _$ s& M5 l6 Z" P* I2 A( ?7 A5 C5 R3 s- L( b
或者
$ G8 X' N: g% p; p$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
4 X9 b) S0 D2 w1 @( ?9 |
: z. j3 N8 a2 K0 b/ P 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):# I( W3 {# ]& f* E6 A) p& M* u
$model->query('select * from user where id=%d and status=%s',$id,$status);
. T8 ^* W- [% X$ T4 @
# H; V' u5 y: m3 h3 T+ ^或者: [ B# E& L+ X5 U1 g8 ]& t* Y
$model->query('select * from user where id=%d and status=%s',array($id,$status));2 b9 [! j1 X6 f7 u9 R4 O8 R8 I9 U D
( i4 v4 Y: }) ~0 I
原因:$ g' l/ [5 @3 }, u: V
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
# V' G8 W% i: E1 g! u ?原函数:, Z; b! m8 u6 g6 n. Y! m7 w2 B6 _; e
protected function parseSql($sql,$parse) {
# t8 ?* W1 O) ?; B- _3 M // 分析表达式0 Z7 [/ l) t$ f& ~; b9 Z( p
if(true === $parse) {
b+ F& y* J! E5 K! H) x. [8 Z $options = $this->_parseOptions();
h; E% {7 T* j $sql = $this->db->parseSql($sql,$options);" ^4 h7 H: ^! {" n x8 a- i
}elseif(is_array($parse)){ // SQL预处理* h! o, l# Y4 J+ A5 L
$sql = vsprintf($sql,$parse);
; ^/ z9 T$ J7 ?2 S/ F }else{& J4 }3 A' D4 u/ M7 b; Z$ H- O, a
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
. a, P2 X# E- C0 A+ T O7 q* i }
2 ?* ]! R% o C2 [ $this->db->setModel($this->name);
5 m- B- ]% w x# U return $sql;
! ]/ i; x9 _- u+ ^: _9 S8 c }1 G; G4 o9 {5 T" j( x5 b" z2 e
1 e8 _5 w/ h7 V9 s5 e验证漏洞(举例):
( D6 s3 ^; l4 j请求地址:
; |* S6 Z7 }. @& @3 b ~% Yhttp://localhost/Main?id=boo” or 1=”1
5 W# c V: v8 a4 l* a3 n/ V T7 u或
% Y' I* o' W* j: E! Shttp://localhost/Main?id=boo%22%20or%201=%221
( _+ w5 g( z% J) aaction代码:( g4 ]% b. G6 r8 o5 ^
$model=M('Peipeidui');9 q; W: \ A2 `7 E' Q
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
# Z9 P2 y1 i3 O, H0 Z" g; i dump($m);exit;
/ G6 s# H+ H7 \& g ]或者1 r+ r# v" X1 h8 ~3 y( N
$model=M('Peipeidui');
0 l7 [$ o: S3 N $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));% D+ [# D/ E* \; ^0 H9 p4 X
dump($m);exit;# U- b! ~( C7 V W
结果:8 H$ ]+ p' x. L2 J' f8 \' O7 L# b/ i
表peipeidui所有数据被列出,SQL注入语句起效.6 Z" C9 C w8 A6 G" \! ]
解决办法:* Q+ D; b" Z4 O9 a: @( I: Q0 j/ o" _
将parseSql函数修改为:; M$ _# P9 r8 F# [6 G, O0 m
protected function parseSql($sql,$parse) {: M9 q! B0 d# J7 w( M, `+ f1 U
// 分析表达式+ o. K# Z3 a: g$ W3 `4 k! W
if(true === $parse) {+ c' p8 }- Z/ d3 H& T* J$ y( W, |
$options = $this->_parseOptions();
8 b' }1 j% D& o9 c: B $sql = $this->db->parseSql($sql,$options);6 S* m1 e( e# A/ L9 {1 w
}elseif(is_array($parse)){ // SQL预处理
3 p8 W" b- P) d U" I $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码7 m& i) H+ Y1 M) _1 h+ W
$sql = vsprintf($sql,$parse);2 T3 H S$ H( w/ m# I4 ^
}else{" e3 E/ n% X$ Q. t# |' a T
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
3 f0 [0 N; k. H: _3 ^( O }" {; U# i1 _: p9 e/ \0 F5 p5 h* }9 E
$this->db->setModel($this->name);1 i8 ?" J. T o. L/ |' h
return $sql;8 V: b0 C7 M: c' h9 F/ E8 f( t# R
}! d7 b& O# @* `
4 S2 e# k" T) e4 |5 \7 D3 u7 D8 t总结:
( Z a* Q5 x3 I1 a) O0 g' Y* P" k不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
0 L( U8 L; j+ X+ v! G% L不建议直接用$_GET,$_POST; D! s) @, t6 z$ d: Z
[/td][/tr]+ a( C+ k+ T! J4 p- ^. C4 e
[/table]+14 H8 [2 V1 P* n( w% F/ H
U$ m1 y% h/ C" g) b. k% g# |$ D% i! z0 s l
|