下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
8 m5 D& X4 V% s5 g- WThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
- t7 V4 y# z5 K( q* b% h根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)4 y3 y: J8 u* u/ ~
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
2 E/ }5 ?% r( R) e$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();. Z, p7 Z% {1 u" w% u- p& d1 k
; ]8 Q2 _: c- [ B# t& d' q
或者 ~% o2 W1 [4 b" b' X9 Y3 p8 ^
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
- |( k+ o( ~) g: u/ w; n+ U8 ^2 E8 V4 R( n
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):* T' H* W) n, v
$model->query('select * from user where id=%d and status=%s',$id,$status);
. S9 ]' ^# G7 M6 r# G: j4 m2 G
- o/ P2 o1 }- S6 e ^或者
7 A4 W" g: C3 f; l. h$model->query('select * from user where id=%d and status=%s',array($id,$status));6 U$ q4 k2 p$ X$ W
M2 ?( g6 s# Z( h0 Y- S2 s
原因:
& R1 S7 P$ C0 q* M+ ]ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
2 r" _" C/ j7 E/ M原函数:
- Z8 v( {8 ~. i* Lprotected function parseSql($sql,$parse) {* b f; h) F7 i" g A/ V
// 分析表达式4 k8 Q) K7 m7 L% D
if(true === $parse) {# S4 ]0 N; o5 l* R& {( [
$options = $this->_parseOptions();$ D; O z3 G. n- R# U
$sql = $this->db->parseSql($sql,$options);% |. }- G: s) [! y
}elseif(is_array($parse)){ // SQL预处理
$ h4 E3 f+ N! u' ^; d8 o2 r4 { $sql = vsprintf($sql,$parse);/ x% s$ b9 Y P. R. S
}else{8 _2 p8 I5 `" C* O! ?; n% X- W4 I
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));2 i3 b9 D9 H" x# U
}, D4 Y Q5 P: b* U: u+ W5 ]1 s
$this->db->setModel($this->name);8 [7 I5 L, z6 z
return $sql;1 y [, U S* a8 D( m* l
}+ H# U: p x3 |- P) C) X
+ o: J9 y+ R& x验证漏洞(举例):+ I% E+ }' J6 F+ D1 I D
请求地址: c/ x9 K+ n7 V* L" d
http://localhost/Main?id=boo” or 1=”1
( \' `( g5 q) o! U' t或
0 F: {( w( X: m) W& qhttp://localhost/Main?id=boo%22%20or%201=%221
" o; Q1 O" D' \ Z5 V' d oaction代码:- `7 n7 f) {8 D) H' v
$model=M('Peipeidui');+ B' F5 P' E% o% q5 J% A3 z
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
' B+ S# I' ]! V4 |: N8 S dump($m);exit;# Z1 e0 g0 c8 w6 Q J& \- e
或者
- g% d5 B* A4 D' M9 U8 n$model=M('Peipeidui');7 {. s6 j. T0 g, d& ]$ U7 u
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id'])); N1 X+ q' J) N
dump($m);exit;4 @+ t7 b) s5 D" C/ z, Q& L' C
结果:0 ]9 I }' q; |4 |. r
表peipeidui所有数据被列出,SQL注入语句起效.: _/ D2 s; t( H. H. `- L/ A
解决办法:- o1 \( S$ L/ a. q" |8 s
将parseSql函数修改为:' N" F* y9 K3 Z" U9 h
protected function parseSql($sql,$parse) {
m) v2 ^% X* |1 y // 分析表达式
/ |# r2 d& b3 Y9 A; a# J; L5 c if(true === $parse) {7 `7 ^0 l2 W V! Q
$options = $this->_parseOptions();" O5 S) t) G: T: X1 Z' n* w6 m
$sql = $this->db->parseSql($sql,$options);
; i4 { ^& c" { }elseif(is_array($parse)){ // SQL预处理# C# A" v& v- p1 k5 H* J n
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码0 C( U2 k9 e) G) J; _7 C) g/ k
$sql = vsprintf($sql,$parse);
4 N1 C x8 a; h- K0 D I! R4 T# L }else{
6 n% t3 v2 s+ ^' ~ $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));& \5 }; j) ~) ~% ~0 x! q
}9 C) g- q7 \9 { Q! e0 X7 K
$this->db->setModel($this->name);' o8 v4 W6 v0 E% N
return $sql;& e# z/ d* t( [* n7 j3 M' Z4 |
}
4 m9 ~2 {: O6 ~8 d% z& m9 x. y* ~2 I' W# U% P7 I
总结:
# `3 X0 E$ X. K) \; G! Z/ D& Y* [不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
0 b \3 O! ?* a n2 G不建议直接用$_GET,$_POST' v# q+ D' x, x) b7 x
[/td][/tr]
. }/ V' M; I# A) q: c[/table]+1, u7 s; i: b) F# t* h, J
% @9 U3 `2 G+ v9 M6 s
0 }1 k, x! G8 X+ S6 |# m) [
|