下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
$ H. Y9 ~* b9 w: E$ D5 O l) t7 vThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件: r( N$ w# y4 Z) }) O) H$ ?
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
- Q9 y" H/ i# _ r8 N使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:$ D$ Q N$ z7 Z8 K- j2 }; S+ z2 ^
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();: t) b% W& q* ]% b& Z0 ]& O6 `4 d
: D7 v% P" c5 d& q0 G; x- Y 或者
7 U+ h* v. t/ _- i% j4 g5 F$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
. m5 S# L0 x0 Y* {' g
: V5 ^8 {4 e. l; ?$ P1 E8 o1 o1 @ 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
% i7 B7 t, e( a$model->query('select * from user where id=%d and status=%s',$id,$status);
( J+ m3 F7 v6 F+ _: q
% L$ H3 \6 |) Y( }或者8 h4 d' Q8 q0 [# P1 r
$model->query('select * from user where id=%d and status=%s',array($id,$status));/ R- g. `+ @$ C$ e, }. x+ W( T$ M
% D6 l ^& T+ X- \3 A. i$ s1 u
原因:/ G( h& ^; E+ `8 S% Q
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤." S X9 E, r; d- v6 h
原函数:
, q4 i/ _$ F7 u) K8 }5 jprotected function parseSql($sql,$parse) {& B) }5 p! g+ ~" W4 ^: N
// 分析表达式+ v3 F# P0 g9 [( L( q, S
if(true === $parse) {
1 j+ g9 \. F- U2 S+ y2 S# p) k $options = $this->_parseOptions();0 s9 A6 L7 z+ K, ?( c
$sql = $this->db->parseSql($sql,$options);
/ P% G" f& d+ X! I* S }elseif(is_array($parse)){ // SQL预处理
6 d( y; p6 P- v% S& t $sql = vsprintf($sql,$parse);5 J' Q2 J+ |* H
}else{9 F, }9 C" r7 l
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));, s0 g( `% b8 s
}! h0 x6 f- u) T$ y( }9 A3 d
$this->db->setModel($this->name);
( P: }4 T$ q9 K$ |: s0 ~ return $sql; M& l2 b5 h% l4 r% G" i
}
: V0 M/ r7 b. J( q! l! X3 y: d( C
9 n$ F& ^; U& Z0 p) G2 Y8 B$ H) v. ^5 A验证漏洞(举例):
f' H2 K! J. R$ ~% h: Z( J请求地址:
" n7 W- w4 }# M# Q: `" C4 Phttp://localhost/Main?id=boo” or 1=”12 Y" W" T' o) Q* `" _/ m
或
/ C- Z1 r3 E% o7 s- jhttp://localhost/Main?id=boo%22%20or%201=%221, i+ k) j7 p& ?; F* s
action代码:
, {% m; ?$ m5 O2 W/ j& j$model=M('Peipeidui');
- y- a4 L4 T3 x# w7 ^$ E6 J; A $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
$ W) |4 ?& @$ }. H dump($m);exit;
3 f* s8 e$ ~$ a! n' |( I% [或者
% q" M0 K6 U2 ^$model=M('Peipeidui');$ f+ ?% `% V- O1 d
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
+ Y& y. y3 ^6 |0 x. [ dump($m);exit;
. X% G2 \7 T% R" _8 C( {! r结果:
7 H7 [! { c; [; P1 P0 I$ i5 K表peipeidui所有数据被列出,SQL注入语句起效.7 q& g8 m$ d$ P! a! y% K
解决办法:; J- c+ Q- m' d1 J" d* V6 ~
将parseSql函数修改为:+ i5 }) U# i0 P% p
protected function parseSql($sql,$parse) {
S; j: ~7 `: f% V2 \1 @$ j8 y // 分析表达式2 k8 x b" U1 u
if(true === $parse) {
* U5 a$ C% F q% Z' z/ t) t $options = $this->_parseOptions();
0 K% x2 p* G6 O $sql = $this->db->parseSql($sql,$options);
% d" T; @* Z( Y o4 c! F }elseif(is_array($parse)){ // SQL预处理
1 v& I) a$ f& M9 i/ O8 y3 d $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
B" c* r. t: y: z) K7 w( | $sql = vsprintf($sql,$parse);
; }; J# T; G' j }else{
8 W( r6 e- P" f* m+ \5 s& y $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));$ j0 v, W* r" c
}) D- j/ C% f* T: `/ O6 F
$this->db->setModel($this->name);3 M4 \) U7 r5 W4 Q2 H# i
return $sql;- Q4 q9 y; z! z0 a- T' v
}
- E, x: ` }: e1 B; G
" U% I9 e5 @) M0 P, C总结:5 h% Z9 h. W9 u
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查0 W3 y7 P8 d. R4 a3 ^; L2 H+ @5 S* b
不建议直接用$_GET,$_POST: n9 B# D J7 g2 o
[/td][/tr]
) e8 b' e1 m& {; f) H0 K2 C[/table]+15 e+ S+ V' @& F9 @2 M, j
4 l: k* n8 C$ _7 Z& b& m5 W
" M8 _1 s$ k P* r+ g; j6 F4 {
|