下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。$ v& g9 ~- N; ]" ~( O
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件1 S! v' X8 D4 @* _! Z
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
" Q" }# w/ b: q& L, Z使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:' q- K% N9 i/ X
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
1 m2 u! x5 f* J0 R. A4 q% V9 w2 P+ l, q0 h
或者
& @8 D2 y3 K: U: R2 S$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();/ m3 k+ v, E8 X; C; ]( S, S
0 p- l# r) ]7 p+ q) \ r, q0 p6 t 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
. d. o c( K7 c( k$model->query('select * from user where id=%d and status=%s',$id,$status);
% y. v- b! Q5 O
( Q5 ?; y. ?4 u1 u5 k( R3 l! a或者: p6 ^% J# S t/ f
$model->query('select * from user where id=%d and status=%s',array($id,$status));! t8 h7 a8 C; t; u( F' r% O9 O5 l D1 I5 U
; G$ V/ y# v5 ]: o3 n8 u& t 原因:
" h- m* {/ l9 n/ a4 RThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
5 q" C% u3 W( j$ S6 R' \4 P3 T原函数:
8 S' G% G8 b) `7 bprotected function parseSql($sql,$parse) {% ^0 L" N! O9 @5 [1 M( y
// 分析表达式
( X0 j1 i& W0 w/ y2 P if(true === $parse) {
9 Y. c! L* F9 M3 e" [0 n& x $options = $this->_parseOptions();
" G! s# Y7 ^/ q( h) N4 \ $sql = $this->db->parseSql($sql,$options);
* I$ g" l) K1 f6 e }elseif(is_array($parse)){ // SQL预处理0 |" q' P! z# g* K* A, a& `
$sql = vsprintf($sql,$parse);- C- a, [/ E% \& ?, d' S' M8 v
}else{( S% q8 U3 B. J+ M# k
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));2 S% A% w0 J+ U& w; @
}7 x! z$ @3 l5 ^3 L
$this->db->setModel($this->name);2 D; n1 N1 I7 p$ R3 L: j# N
return $sql;) H2 u4 P7 l" [4 g* F: j, V" ~7 b
}' B( X* h9 z$ A
( {! G' b7 D N B" ?验证漏洞(举例):
; B5 p, t/ G& X+ F请求地址:/ f6 K' \3 H1 I! }( F9 _- g
http://localhost/Main?id=boo” or 1=”1! R9 o8 b9 R+ P0 g$ ~1 g
或) B8 F1 ~$ _$ q" r
http://localhost/Main?id=boo%22%20or%201=%2211 J/ w4 _7 ?! I% F; v
action代码:0 I( w! i# I" y$ z, J
$model=M('Peipeidui');( U4 _! g) c1 h
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);7 Y+ Z3 O4 K! F I
dump($m);exit;
# x$ L' q. V9 Y8 X9 G1 ]* n* F或者
+ D+ T- _8 R5 V' L$model=M('Peipeidui');
: ~( s% V c5 K+ X3 p! { $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));. v# {/ C$ x5 n3 i# C' e
dump($m);exit;
1 w* E0 {* M# |5 C+ r% T: I! y/ G结果:
" p2 H9 I7 W! ]8 z( e2 M表peipeidui所有数据被列出,SQL注入语句起效.
# {) ] x6 p- }- @解决办法:8 Q$ F8 M6 j2 Q! W, }
将parseSql函数修改为:
$ g1 h) u. A+ X; k3 ~! V7 Uprotected function parseSql($sql,$parse) {1 Y+ L7 g2 V% {9 W
// 分析表达式
+ l- V4 H# J- f8 p( w' c8 _+ \ if(true === $parse) {, {6 Y( Y) k2 B9 v
$options = $this->_parseOptions();$ x- e* o+ Z1 j+ a9 K$ H d- f6 I
$sql = $this->db->parseSql($sql,$options);
! L+ P% w9 H$ d; { }elseif(is_array($parse)){ // SQL预处理
8 K. V$ |9 `% K $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
- i3 ]! b d. l7 V $sql = vsprintf($sql,$parse);! o; _/ [* ?* O$ S* M
}else{2 u8 n; K7 U; q0 e! v2 ]8 w
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));7 ]- ]7 e3 h6 c
}6 l* r8 L% F9 y( m2 D
$this->db->setModel($this->name);8 z4 ~" w" {5 |: I+ ?3 {% j l7 p
return $sql;
& C/ E* p4 v+ `) Q1 E% R$ F8 ^ }7 r A" c/ \* ^2 s( ]
3 y+ A8 o& p' p/ L总结:# c; {" [& }: E/ R; i4 J8 G
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查/ P; p: j* H' x3 O3 `+ x7 Y
不建议直接用$_GET,$_POST I" n8 u# ^% r. K' V6 ?
[/td][/tr]
8 ~, t; Y0 i! B) q% j[/table]+1/ z8 {. r1 _) _! P q
, Z$ G6 G* E6 [" x. G6 H Z
0 i& Z, D% [3 {, O! n* ^' u$ [, u
|