下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
P% G4 s3 {" q# P" TThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件' }/ R# Q9 e7 ~. h' M9 g u
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
; C; g; _# Z4 ]3 F4 W使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
* f$ }2 J; q; O5 [$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();' L1 r- k! ^4 u6 ~
3 H2 c- @, W" q; n 或者
8 A# c; ^( \: q6 d6 _* G$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
9 s- g0 b' X- A' ]% l- B$ x2 Q# x% H
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
; }9 w( ]5 t/ r4 _# Z8 X6 \$model->query('select * from user where id=%d and status=%s',$id,$status);
( d( n! E4 Z8 h1 |# |6 G1 X/ v- c9 F3 ]0 Y* [7 O
或者
/ }/ N/ R; C8 ?$model->query('select * from user where id=%d and status=%s',array($id,$status));9 i5 @6 ]2 X' c1 h% r
6 M' o6 o9 [6 L' C
原因:
5 d# g4 K( ]( d6 ^1 aThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
4 U Y8 `# l q1 n6 y9 u; A! s! E7 _原函数:
5 Y6 m4 D% @% ]+ w( t. z' \protected function parseSql($sql,$parse) {7 R5 c1 W9 p$ v7 J/ M! d
// 分析表达式
5 }9 b: G' @& L, T" U) e B if(true === $parse) {4 ?0 t0 e7 a, i/ c/ Q6 {
$options = $this->_parseOptions();* X# N8 d+ `% z: [" n' W
$sql = $this->db->parseSql($sql,$options);# i6 o& ?# }' W$ f7 L; v* X( h
}elseif(is_array($parse)){ // SQL预处理
* ]+ N H! F# U( M; o $sql = vsprintf($sql,$parse);/ C; K1 E% R. ~ x
}else{
: q6 m' }2 g" z) z# o* J8 F$ ~( N $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
0 c9 y2 M9 A2 F- F* a }
6 }. k7 @0 D- E $this->db->setModel($this->name);4 x2 D6 l1 ~! l+ A
return $sql;
) e6 R0 ^: K9 P$ }: q }
& O1 u4 \( K3 R- i
% i2 r9 p. [5 _验证漏洞(举例):
8 Q* y+ r% y% c' k* ?; ~5 W请求地址:$ f0 P. P! X1 u* h
http://localhost/Main?id=boo” or 1=”1
: Q; j4 C8 T9 \# n: X- Q5 L或
1 f, x6 k! z& u7 C( Shttp://localhost/Main?id=boo%22%20or%201=%221
% S3 A/ W7 e% P; N5 ?8 _action代码:2 W& ?* P O* |* N
$model=M('Peipeidui');
' s9 r* E) O$ j6 r, ~ $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);* n, j, s/ F$ F7 a: |6 n
dump($m);exit;
& f4 t' s/ O3 Q' r! n或者
* q8 d) H2 P2 f' f6 b$model=M('Peipeidui');
1 p) q5 t8 Z) a0 j% U $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
' g3 V ]" s* W& E+ N% E dump($m);exit;) X4 R5 j$ ^2 A. c! M
结果:7 q! }* ^: p# {
表peipeidui所有数据被列出,SQL注入语句起效.
0 v. J( P' b$ J! T0 a# ^/ F解决办法:
; d4 U# Z/ q1 _! U+ E将parseSql函数修改为:; S6 \- Y5 X, g6 E3 H( B8 T; x
protected function parseSql($sql,$parse) {
6 n$ n& h, T$ V1 X1 a // 分析表达式' G, `0 H: F2 Q) q& L
if(true === $parse) {
9 e, F2 I+ i$ I $options = $this->_parseOptions();! T% d4 {5 I/ Y6 a$ e2 J8 f' ^$ M+ W
$sql = $this->db->parseSql($sql,$options);/ X; Z8 v0 U3 y- z8 c" {( B
}elseif(is_array($parse)){ // SQL预处理
6 }% q' o+ z' T+ M $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码8 ^% t+ ~2 o0 Q1 |
$sql = vsprintf($sql,$parse);) d! q* l% g4 ~' a& N" [7 o* ~$ y3 T
}else{. Z; G. ?8 k8 O* g) S
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
v: }# n) a2 O- p( t }, r3 W9 ^" V' |% r# b1 o1 }5 x
$this->db->setModel($this->name);* S7 m: n2 S1 A
return $sql;; O, O- Y' j# [. q0 |( s! Z& q
}
- Z: q) O- Z5 r8 j# `% D' o+ C1 T! e% g! r& x# `* X" E7 N
总结:
- t( g/ P2 k4 Z; L' T3 t不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
% t |- {4 g7 j7 V8 L% ~- C: Q不建议直接用$_GET,$_POST
/ x7 X' F3 K- F( y5 j( ?[/td][/tr]* W- J0 p! m3 i7 s8 @0 L4 @
[/table]+1
; F; y. ]- j9 b5 V. y
8 G0 o8 o9 h- m% U' G# ^
# w8 K' l! C4 p$ P$ _ |