下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。* t; _' x* z+ A4 n* V
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件" V; c5 @. j/ A$ F0 d( o
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html): g) P4 X; j7 j" b& _3 O9 w
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
" |- h( R" `8 r1 P; X: L) W/ ?( Q6 x$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();; P$ t J4 ]- P
' v2 P9 f$ x4 P2 {7 I9 p. k5 _! n; B
或者
' c1 W9 S1 j7 f# A( T7 [2 ^$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();$ L% b1 V) h# T: q- O5 p( y
/ m; W; ?( K" _7 { 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
4 ?- Q- r8 d) F) x$model->query('select * from user where id=%d and status=%s',$id,$status);4 Q7 L6 ?, k! X* L" l9 H
3 i3 C& m5 e) T+ q# k
或者
e# j o$ A6 ^: @ K6 n2 F$model->query('select * from user where id=%d and status=%s',array($id,$status));$ z& |3 ^- v; }/ K; X6 U8 C
Y. v( l9 s/ [7 q* w$ ?- Y 原因:4 j- p7 }* s* F0 ?9 _! P
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
. }' {1 q- J' o- J' Z g原函数:
! x1 X: w4 i9 @9 `! ?$ Xprotected function parseSql($sql,$parse) {
: r0 z9 Z, @1 h2 ~# `: [ // 分析表达式
. K6 q2 k( V' p& S1 q4 P8 ? if(true === $parse) {4 _% w5 \1 k9 R& H/ }& q
$options = $this->_parseOptions();
* K* W0 B! Z+ o" u ? $sql = $this->db->parseSql($sql,$options);( j9 d6 A) K: [9 `4 w
}elseif(is_array($parse)){ // SQL预处理7 Q6 D* W" \) H5 s# y
$sql = vsprintf($sql,$parse);* I9 q: h! S5 q9 t9 \
}else{/ y3 A3 X2 y9 D9 @$ d
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
% f% m* L q- O' Z! x }
. q% X' v( L, r7 `2 | $this->db->setModel($this->name);
" W# T# f( X) y. ]" G return $sql;
0 N# G+ w7 E' m' q( ^ }0 Y) M' ^. {4 R/ N. l
( }# I* s" M& ^6 Q
验证漏洞(举例):
. D* p8 r: z4 @# E" D4 E请求地址:3 [0 b* a- R( E) C
http://localhost/Main?id=boo” or 1=”14 U+ J4 s3 l" x9 Y0 U/ o
或
6 d2 V; O# K! G6 W, D" H. g; Q3 ?http://localhost/Main?id=boo%22%20or%201=%221& u& S) L% V1 p# s' O% Y% c, X
action代码:8 }* g5 C) ]) k8 G0 t: ?
$model=M('Peipeidui');8 R( E; i7 M) b2 L
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);6 y" d: M: N6 `
dump($m);exit;
! `) ]- p% o% b- F或者
$ ?- I! [4 E/ `6 C N# X$model=M('Peipeidui');
9 M0 g3 Z4 N8 J0 ~( f $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));( e/ ^1 g6 B }+ m
dump($m);exit;
1 |3 F; d# z2 S% V' |" B! v3 h$ E结果:
+ W( }: q5 Q; L表peipeidui所有数据被列出,SQL注入语句起效.
. n* Z( r4 J5 C/ N1 R' o5 ^解决办法:, f' D, q P" n) N# g& S1 T4 p2 F6 U2 S
将parseSql函数修改为:: n& Y- M- k. j. z, _2 c
protected function parseSql($sql,$parse) {
8 w/ ~- K4 l! }7 v // 分析表达式
* W6 V5 }4 N% _: Z if(true === $parse) {
0 S i8 |: i" S r& W$ G% H% X $options = $this->_parseOptions();; L: w; n4 }- p; `- V( l# M
$sql = $this->db->parseSql($sql,$options);2 `7 j0 f: D* p( {4 a5 M I
}elseif(is_array($parse)){ // SQL预处理
7 F, k8 H- u0 g6 `6 `7 y $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
% e8 T7 O' @# k4 ^ $sql = vsprintf($sql,$parse);
7 ^" {4 L7 y z4 {0 i- \ }else{7 Q# G. t% C) m8 O" @% M# X8 R, x, q
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));7 S4 h" G2 h& O5 T
}6 {' G, F# e) d9 g, p% S% K
$this->db->setModel($this->name);0 @# H- j% S' q+ y
return $sql;, ~3 d& e0 i' @. O
}
( m% @/ _9 a b4 y) N$ V& Z. I+ s. j
总结:6 n( ] k0 I F+ n& b
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查9 Q# R: V4 m. X p+ h' T
不建议直接用$_GET,$_POST' [5 b e) Q+ |
[/td][/tr]
5 |0 a0 }. ^% |; e! ^" K; u, w; W[/table]+14 X7 L& T- V' M/ i+ A
7 q& `5 `' w6 U& R$ |6 e
# z. Z, @( K& m; [/ V* U' V
|