下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
! a* o. V, V/ }" ?, E1 V: ^2 C3 lThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
1 _+ |( @0 e6 g+ G根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
8 ^; X/ p; v/ L% D使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:+ z/ T3 Y4 L. E" ~
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();. A# n( f) C- z) h2 f! l
- H; s0 T9 Z. r- W) A+ c! V 或者2 T6 N5 P! w! c# I
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
3 T( l. t+ U. k1 D' L4 X
) N5 X: z) J% Z! z 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
; r. {" h- w2 b5 W7 F: ?$model->query('select * from user where id=%d and status=%s',$id,$status);
( P! f: Q0 b7 z" H2 Y
) L3 ~. [# o& J& W: c, E; [* V或者4 @- o G0 G+ z7 |1 I
$model->query('select * from user where id=%d and status=%s',array($id,$status));4 Q- d' i6 e1 _! ?+ I
1 @" e& A' ^! E' ^5 g( u, q 原因:
* p! |; N; d- {3 ^/ G3 IThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.; o- M$ ]) S& e* L8 t" y2 f
原函数:; q% t. P% ?* o, F* u6 h
protected function parseSql($sql,$parse) {, g; D4 A: k( {' m1 B' w5 h ?
// 分析表达式
& d/ [0 f' B" c, S if(true === $parse) {
. t7 h; I0 X' w8 {! R8 a: g# M/ o $options = $this->_parseOptions();
+ j. X, s& `6 Q2 ^4 A3 M; H $sql = $this->db->parseSql($sql,$options);1 j" p5 Z! y5 e% _
}elseif(is_array($parse)){ // SQL预处理
8 T( R: C [- S3 t $sql = vsprintf($sql,$parse);
- z) v) P& A) x+ U J) G: [ }else{
% E- P+ ^& p5 x2 s" p! C. a $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
% A6 f; f6 v+ F) E) q0 P/ a4 m7 n }# w& W- e7 [* a( z
$this->db->setModel($this->name);3 q6 \8 y1 m: B5 F H# k6 n! }
return $sql;
9 s7 G) [0 K, R0 c* \) ~5 o" Q }- A% j% a, b/ p$ H v
& Q2 w( Q q, c. |2 c& M+ X
验证漏洞(举例):# [2 j4 K. c4 L: H( s0 F$ G
请求地址:$ y6 m) D3 ?3 X7 P& |" {
http://localhost/Main?id=boo” or 1=”1( l0 T+ w% h% ~# ]
或+ z8 b7 c+ W* O- B& Z
http://localhost/Main?id=boo%22%20or%201=%2211 o( V" K/ |5 O/ F
action代码:' ?9 E% e6 X5 P3 p r5 n
$model=M('Peipeidui');
; M+ d- l6 }! {, c! g4 g $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
% r3 d+ k, Y- ]+ }. w2 T4 c. |3 F dump($m);exit;
# ^7 \5 ^* l! y8 b; e3 a或者4 R" [; v7 L) X7 e; ~7 N
$model=M('Peipeidui');" j' g" I c6 }! v9 U6 w
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));. L- e& l. ? r. H$ [) R' G
dump($m);exit;6 m! }% Q' i& X P0 f) P9 G$ p- x
结果:: z( O: P% B1 O7 \4 S! [
表peipeidui所有数据被列出,SQL注入语句起效.8 |$ g e6 `( Z% t/ S- ^0 Q7 a: p' z
解决办法:: P) g" C7 K! C) \
将parseSql函数修改为:
# v$ D9 L, K3 N. f4 Y. l8 J6 {. W% hprotected function parseSql($sql,$parse) {
/ b) s" Y4 Q7 E) k% k' S" l // 分析表达式
, F s6 h: C: j( v if(true === $parse) {
# h2 ^+ f! v m# e$ Y3 u4 |! K( @ $options = $this->_parseOptions();
: a& f% {& O, k& e $sql = $this->db->parseSql($sql,$options);
Q/ }9 y; R$ e+ m& j }elseif(is_array($parse)){ // SQL预处理1 F& k6 ^0 ~# t. b$ R
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码 [- a/ K$ B, a* r1 o
$sql = vsprintf($sql,$parse);3 `6 N1 W1 ^' x
}else{; T0 b: u: V% \1 W; i7 ?/ m
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));; ? s1 g* A, [! f9 H8 I
}* A0 |& ^( }: T/ M/ k/ F
$this->db->setModel($this->name);) a4 |8 T0 ^& O" B* w
return $sql;
) L" y. P1 d* e/ Z j: t: I4 }! } }( H9 B4 r/ Y2 E9 ^+ p4 Z* _
- ~. E* m9 h/ J- X: M' P4 Z总结:3 H t" A& m% s" s+ C. |( V! Q+ E
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查7 w- Y l; j I, d6 |
不建议直接用$_GET,$_POST; [/ w% w2 ^/ B* l
[/td][/tr]
; ?; ]8 @3 C" C. }" L$ L8 S) d[/table]+1; A5 J: l6 k p
' [/ o; O, m' w6 ~( Y; y8 ~2 H0 P9 O
|