下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
3 Z! k1 s$ T, T$ y; lThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
. L9 M/ w V! d4 D! k7 G根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)3 ^6 a0 n1 \- ^: z% Q+ ~7 u$ X" f" `
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:/ s& I) b0 F( ~$ U8 _
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
; ^: f1 t/ h; q7 B8 k8 b0 K, w; n. o+ x+ X8 o$ Y" c
或者* i3 d* g9 t: f: Y
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();2 R; u" x/ d* O4 R' w
6 m; @6 h9 Z# B9 b2 b L) ~
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):8 S0 k4 G% | z
$model->query('select * from user where id=%d and status=%s',$id,$status);
( s& T- `4 G$ f9 \' E& N3 g4 E& y. v( L6 l
或者9 U/ c7 B6 L' }1 h# b6 t
$model->query('select * from user where id=%d and status=%s',array($id,$status));9 P* w* d% X7 c' C, U# ?4 @: p. w
; o& R4 P- m1 K: t5 ~ 原因:) [$ i. m: m7 J- e( R
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.) G3 W/ D5 s8 `1 S. `
原函数:
" S3 w' ~, V* m- @protected function parseSql($sql,$parse) {3 _- x9 }& \1 G3 m# e
// 分析表达式
3 ~; f6 u& ^. w$ x# \2 h" t+ D if(true === $parse) {
) H+ S7 x; i* p. ~! K. _9 c $options = $this->_parseOptions();2 `$ a; J2 o+ O s$ {7 \
$sql = $this->db->parseSql($sql,$options);- c4 Y& \. [7 Z$ L$ e _
}elseif(is_array($parse)){ // SQL预处理2 B/ _* h* V2 M3 J& S" z' \( `
$sql = vsprintf($sql,$parse);# }* _8 f, A: u% A
}else{; h6 D* G( p8 Z3 `3 n
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));# p H9 ]# ~- E2 H
}1 Q6 G1 Y' v$ @9 B5 Z
$this->db->setModel($this->name);
% X6 D1 s/ j; p: I/ ^ return $sql;* G3 E- ~. y! P% P7 b) D
}9 \0 e; n, I* L; d* z! M
6 \- s$ L: C8 e
验证漏洞(举例):& P+ y, U! G7 M( r9 W. O
请求地址:* f4 K( L2 u$ G& o. h G' E
http://localhost/Main?id=boo” or 1=”1
1 {( R7 }5 _9 B: k9 i5 o" r c5 H或
% A/ b: z4 e. W, n4 thttp://localhost/Main?id=boo%22%20or%201=%221
3 ^4 \) d& y- L Xaction代码:& P+ _. ~% D9 j z) ?
$model=M('Peipeidui');
1 ?5 ]0 D. O) S# \ $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);3 h) j# J) R1 i+ v' q- N
dump($m);exit;
$ | U4 i$ L8 m9 }3 R或者( X( \8 I) a- X6 }' X
$model=M('Peipeidui');
. n, p. ?0 s) w( I $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
$ ?* z9 X: @/ \/ A, F2 S3 U0 h; E dump($m);exit;
5 \2 u! L) y" q; J- L6 l结果:
9 L6 J$ n' F, e) q, A) j# r5 t5 T$ k表peipeidui所有数据被列出,SQL注入语句起效.0 `; k4 e+ [6 }7 `0 ?
解决办法:
% I4 o" K& s, A将parseSql函数修改为:
+ J% X' ^+ j$ C5 K! K+ X9 iprotected function parseSql($sql,$parse) {8 t& [' R* L2 p, ^, W
// 分析表达式
* R" z! p1 E# F' A5 |, e% G if(true === $parse) {
, P; o! h2 h% S7 ^7 C0 V $options = $this->_parseOptions();
`0 K9 R$ E( d t A $sql = $this->db->parseSql($sql,$options);, X, w* D& @; `8 S. p( P( i" V
}elseif(is_array($parse)){ // SQL预处理) R5 y9 c* }9 Y* x- g9 T
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
9 V( X, M2 W6 B& X) J1 }# P $sql = vsprintf($sql,$parse);0 ?& e _; x) |5 m6 |* [( j, [
}else{
& G5 o2 c+ h; I0 Y$ ]5 J $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
6 s5 ^1 v; \+ L2 |1 A } W) H8 r% b# R+ e7 U
$this->db->setModel($this->name);
, Q) M _( g8 H$ |2 V, k return $sql;! y2 [5 U8 S) X' k8 P, b
}
$ U& e# G) K+ d! c/ r* u9 J( @- d) f6 N) m8 J3 L. c+ q* G9 C4 i( {
总结:
4 g% R4 }; T' o* W+ U不要过分依赖TP的底层SQL过滤,程序员要做好安全检查; u- @4 @3 `: O% A* c% r
不建议直接用$_GET,$_POST9 J% v( n. O+ P' W' w
[/td][/tr]" D% Q+ _) Z/ Q0 A0 k
[/table]+1
& d M/ H/ @" `8 O
9 V/ V R- x! U4 s( U9 A5 ~' p0 S/ s6 R! T
|