下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。2 ^. u' n" W5 ?2 k6 z" Y3 i/ Q; y
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
- \* n) }5 I, t根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
& g1 G a( ]# e4 n7 u( U$ }$ ?使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:2 K3 e$ }' W$ y- }7 s3 r
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();, i# I1 |* j$ S, Z7 u
3 F' P5 R+ M& p- ~1 d
或者
5 V: w* S* T3 n! b" D$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
$ @- Q" K7 U2 G% X7 h" r
: `9 ~: V4 R: }( x3 R 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
' m( h/ D- m) ^$ C( M* }$model->query('select * from user where id=%d and status=%s',$id,$status);8 `% s" m, J6 K; Z% J
. E% s& L R9 q! s! T5 u
或者
Q8 y/ o: C% s0 ]$model->query('select * from user where id=%d and status=%s',array($id,$status));% A; S* O( r' V. E
6 \6 z7 K4 r' \ 原因:8 W, e/ q! G- {6 _
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤." {# O5 M) J# h5 A9 i2 k4 T
原函数:
+ }& M2 F& _3 sprotected function parseSql($sql,$parse) {
$ |, f& Z4 G5 X$ W$ N // 分析表达式
0 H5 }9 o3 R9 Z. r |8 j- E2 Y5 h if(true === $parse) {6 f) z( r! |/ J3 [0 g
$options = $this->_parseOptions();
/ Z: v! e ?& d; K3 H $sql = $this->db->parseSql($sql,$options);
+ C* F6 l% z0 f# K0 H% j }elseif(is_array($parse)){ // SQL预处理. E4 L, |( O3 Y! w2 R7 s Z- y8 a
$sql = vsprintf($sql,$parse);
0 @4 Q a7 @1 L9 t8 P9 s }else{7 z6 O: ?; V' R3 V- G' @- K3 O
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));( F& z- ^1 B5 D0 ^8 R
}
9 P; i, i, g: e' ?+ o I $this->db->setModel($this->name);1 f% \0 k0 v, R6 k
return $sql;; g* v" u! [1 k* R% Y/ c; g
}' l+ J# c) `* J6 r
% u4 h# |7 i7 N2 d6 [! A
验证漏洞(举例):5 a" B/ x7 Y/ A) P1 l$ C; r2 H
请求地址:0 L7 ?# ?0 P8 g. c2 X
http://localhost/Main?id=boo” or 1=”1
' v" M4 x9 b' x6 D4 ?* b或1 t! r! [' } Z' V
http://localhost/Main?id=boo%22%20or%201=%221* O, v; n2 \, K: }' R- b2 q6 K
action代码:4 I1 Q0 o6 x! A5 i8 ~ p9 J1 H' d n7 e
$model=M('Peipeidui');
* s1 h6 i: d/ g $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
) u$ v1 E; O* a dump($m);exit;
8 H; W( x. f% m% K$ i或者
" V* p& V2 W* H, Q. g. h* v5 K$model=M('Peipeidui');4 P, t3 b# j+ U0 |* V+ P
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));1 M* m" l6 L; ]' [+ x* y3 x
dump($m);exit;% I( B; ~0 t D W) q
结果:
' d, y+ Q2 Y1 T C. T表peipeidui所有数据被列出,SQL注入语句起效.
2 ?8 W& ^5 f5 j! F9 f6 p解决办法:
7 W: d5 g' N* p- N( |4 d. ]将parseSql函数修改为:
" S% H! V4 ?+ R0 Zprotected function parseSql($sql,$parse) {
8 s/ X, E5 t3 m7 Z" ~% z // 分析表达式
- u& O) w. m3 O u8 O1 X! J$ ~% K if(true === $parse) {
% H; Z( S1 u4 }- J o $options = $this->_parseOptions();
: P7 t; K4 \, O3 W' {: C1 \ $sql = $this->db->parseSql($sql,$options);( W& }4 W8 d }2 b: }8 w) q
}elseif(is_array($parse)){ // SQL预处理: L; F6 h6 _: f
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码6 K7 Y' j1 d# s& q% _3 p u0 c
$sql = vsprintf($sql,$parse);$ m8 C- [: y0 f5 b- F# D1 v
}else{
% V2 h9 `6 h! P% M) G $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));. O* ]) C- i2 G& b' m4 J1 y3 a7 o! M
}( n3 d f6 S( `
$this->db->setModel($this->name);
* ]: [$ D: g+ t) m: b2 j& F return $sql;
4 D& s8 `8 m! E Z( B }9 o5 `: P& y* G
! u& i0 E$ p: y8 o6 P: X# \( A总结:8 \5 C! D' b9 T; j+ i5 K: |. ~
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
1 q7 Q$ S& ]2 Q( W5 O7 R不建议直接用$_GET,$_POST- E( c3 i6 f' s d! H
[/td][/tr]& e9 l; q" S: l# q% H9 ]
[/table]+1
[* a) y7 p$ b. }
$ d3 Z( Z! S. Q; `
0 |- m3 F1 h5 o* s: G9 r4 W, g( ^+ ^ |