下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。) q5 v. W A7 r$ M# l$ J
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件8 g5 r6 [; { S V
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)$ c4 w8 E3 R: K6 w$ _" J5 J
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:; t& O5 Q q( f
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
/ j) L1 a& F0 e3 [: i# k- Z: G% P% ]) \) `# V2 I
或者
0 y4 p2 U& F3 t$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();( e# q* Q, n! X% s. ^% a) A X
6 e' h: U& D" l+ o0 g. u# B 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
" z1 C9 e3 [# Y8 X( p8 H$model->query('select * from user where id=%d and status=%s',$id,$status);
9 G u7 a# r2 B* S1 }/ B8 }$ L0 Q1 o. `4 j% W& C! p5 y4 q
或者
6 Q, r3 [' F/ N# T$model->query('select * from user where id=%d and status=%s',array($id,$status));
6 S% q" [* D; e1 S0 M7 c7 h) {/ y# g+ F
原因:
' V* _( ]. t) \$ w7 v8 N! yThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
1 @ H! `: y2 y! b原函数:. | y! E, m- V0 |7 c/ K
protected function parseSql($sql,$parse) {
9 Q' P0 i. a9 f* o. D // 分析表达式
" H! C3 E. P: _; s3 d3 d9 ^ if(true === $parse) {; ^. N% U6 y; r K5 m
$options = $this->_parseOptions();
+ ]# T5 m* x6 ]9 k G- Q $sql = $this->db->parseSql($sql,$options);6 o1 \6 B# l) g1 n2 {6 |, ]
}elseif(is_array($parse)){ // SQL预处理
4 p5 A, \+ [5 i. a l5 X2 j $sql = vsprintf($sql,$parse);
& a7 d3 E4 F; j8 |" R }else{
3 O4 y4 o$ d+ h+ \1 u) F8 n/ v $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
# U# g. A9 l: t. z! x. J" Z; k5 ?$ x/ ~ }
" P7 r" M* Z! D. E$ Y) M7 I $this->db->setModel($this->name);0 b+ s' C) N+ k( l1 A" j O# g
return $sql;2 {2 h- J6 D2 z1 W- J8 I
}
2 s% M# e6 \1 ?7 Y1 ^2 w
) H$ `# }. B' `2 z. Y; K验证漏洞(举例):0 F. [0 F, o% A- f/ Z
请求地址:
% q; m7 m" ?4 k! A; h3 e6 yhttp://localhost/Main?id=boo” or 1=”1
- Q" R- p- z; K6 @* c0 B或
0 u s3 o: ^) H2 ghttp://localhost/Main?id=boo%22%20or%201=%221
6 T1 k, K% ?# m; I' yaction代码:
2 w; I' |9 ?: m" Y5 ?8 S2 o$model=M('Peipeidui');
@0 k4 _6 l2 ~3 I: j9 X $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']); Y2 @' y$ ^4 V/ ~0 l
dump($m);exit;
% ]! j0 p% M( V或者
$ ?% ]' v6 Z+ }* v; X$model=M('Peipeidui');. M' q, ?0 ]; S. x. ?3 v# U5 a- o
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));' L1 U# F8 t/ D: J
dump($m);exit;( b8 ?. K b. x- U3 c: k$ ~9 ?' o+ }
结果:
$ C7 \# Q$ u. I+ _4 P( S表peipeidui所有数据被列出,SQL注入语句起效.
; T ?( G0 e7 ?) Z1 X+ D' ~解决办法:
/ M; q+ |/ _# R7 |! b将parseSql函数修改为:
. p3 _5 x n" _. `2 k6 C. W1 |protected function parseSql($sql,$parse) {
1 v! q1 t: H' U, t3 C' ^ // 分析表达式9 J& O' ~' ^; ?( y1 `
if(true === $parse) {% f1 V8 T2 ~7 r2 a! }
$options = $this->_parseOptions();
) p8 r# i1 b: [8 J3 x $sql = $this->db->parseSql($sql,$options);& P3 e' D& I7 t3 k
}elseif(is_array($parse)){ // SQL预处理" a+ c Z7 m0 y
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码+ _, k% q9 h, [5 j( a
$sql = vsprintf($sql,$parse);( t# m- [1 F/ c+ ~# \% G$ t& l) t9 |' k
}else{
9 z5 \4 F+ j* t, H# X5 L" n) l $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
9 T5 [* j& A1 N' X& q1 n/ J! | }
$ [& g5 u% a! Q $this->db->setModel($this->name);
. P/ m% D; Z6 C) Z0 J# D4 b return $sql;
& ]" p K5 M: P; T* V! v$ V, L' f }2 Q2 x6 t) E c. K! B
6 F5 n: e2 K0 [! X
总结:
|5 z6 e, X& k+ h) L! D ]不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
' v3 h- r# {' ~ u' U0 Y' p不建议直接用$_GET,$_POST2 V; s1 s1 [$ i! K
[/td][/tr]0 B, x1 `! B/ M" `7 W$ N
[/table]+1
; i& a' w. y: X4 [
6 }( h/ z/ N) ~. r$ R0 U& M& j! r; }+ o1 h# m+ A3 X# {8 _
|