下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。+ t! U9 C( d* \0 C1 h! x
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件9 b- L4 V# y$ y$ ~- {. ~/ q/ J5 A
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)" z$ A/ t- P0 ^; c
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:* K& W6 x5 i4 d% Q9 q+ d
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();3 ]/ i* j( p! B0 c% Y
4 l& y- i k/ @4 g8 R1 y
或者. F$ c5 N {# O$ F2 [7 K, R/ w
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
+ G: ?& }# U' H+ d% k
! c4 L4 |7 _: d9 f 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):% c! J+ f' ? Q; R' E) U( P) ?8 ^
$model->query('select * from user where id=%d and status=%s',$id,$status);
& _8 Z$ [4 W) P% G" d1 H
+ }8 `7 Y# M" D" o+ ^* m或者2 X; [2 r; x4 r$ {7 u
$model->query('select * from user where id=%d and status=%s',array($id,$status));( p+ f1 o5 U& o0 c4 Y& s& v5 I
2 v5 d2 o$ z$ a8 p E9 S
原因:
) [ \. ], J5 s/ C- p) V# ZThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
1 @& z2 a) _% H; e! _原函数:
, k8 c* M- j& w& Cprotected function parseSql($sql,$parse) {
, u7 V/ s$ a' q* H" x // 分析表达式
A5 F& k4 _8 \" ^5 n if(true === $parse) {
3 j5 r, l0 A/ Q! v; s. E* } $options = $this->_parseOptions();3 z9 E* @( E9 w6 d* i' p
$sql = $this->db->parseSql($sql,$options);) _4 q9 D7 H& }) F
}elseif(is_array($parse)){ // SQL预处理
% M6 O1 u2 n# }1 e0 s5 R: g, U% [& [ $sql = vsprintf($sql,$parse);: h6 W2 O/ v' p
}else{8 M Y+ T) p0 j X! }3 h2 V" C
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
- i* |8 Z% N% u& y4 _& A }2 Y6 \7 t* a& E2 ~4 E
$this->db->setModel($this->name);
- r4 h% [* v& Y* s return $sql;% ]. ~2 A& V/ \0 i2 l; O
}3 a3 O8 p- X1 h- y$ I1 a
7 \5 d, A. y; g) s- N M验证漏洞(举例):
' _- u* v. f8 n/ q+ r请求地址:0 N) X' r. V6 Y% y$ V
http://localhost/Main?id=boo” or 1=”1
) z! u6 X( Y1 z; ]3 a7 v或2 p5 i6 U' \2 F6 s& h
http://localhost/Main?id=boo%22%20or%201=%221
. e3 o4 P. E9 K8 D8 eaction代码:( k4 }, M/ G* E* U1 d0 p& u7 t
$model=M('Peipeidui');
- y" E( L& N$ I4 Y4 j& f4 [ $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);) F/ [ u q: c5 x' t
dump($m);exit;
4 B: T: R/ ?- H& S或者/ X7 ?; t/ v6 |
$model=M('Peipeidui');: @; V( d. M8 c
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
% z7 m+ i8 ^' L) u ^; F. F( k dump($m);exit;
( Y6 u6 w( N5 W% A) y* ^" a- Y- L结果:3 u- k0 L- N7 K+ y
表peipeidui所有数据被列出,SQL注入语句起效.
7 c. C- g4 h8 H8 F- f: t" u* @解决办法:- a9 s( a( ~% t. i
将parseSql函数修改为:
" A4 ~9 t r0 j" lprotected function parseSql($sql,$parse) {
% n2 ^# u: ] \6 r+ u. { t // 分析表达式
$ Z, C" `* R( a8 @$ o6 J7 R! W if(true === $parse) {8 G) r+ t1 v' v& y( q/ f
$options = $this->_parseOptions();
; c' r! O" R) K: r2 f9 R0 I$ t $sql = $this->db->parseSql($sql,$options);: ^8 A5 c0 z4 d
}elseif(is_array($parse)){ // SQL预处理
. Y I) N# F$ C0 W $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
6 X" e: k. s0 m" f+ T $sql = vsprintf($sql,$parse);# {' L$ J7 k, M5 d" L! p0 Z
}else{
' f* ]3 R8 ^; C/ W, v( z' k6 g $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));: i6 o( A: P- r6 B$ S, V2 z. ?
}* A! z# g7 A# O1 u( p
$this->db->setModel($this->name);) `+ h5 ~, a& U0 a8 l' s2 ]
return $sql;7 {, r3 u0 l, @+ u$ h3 A9 o& m( h
}2 X8 R, p3 x: N; O+ b$ \7 U6 s
j. O; ]" S2 _3 Y总结: _' U1 k) W- R
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
* V* Z t2 Q- U7 E不建议直接用$_GET,$_POST* F* z. Q# k) o3 ?3 ]. a2 w, N
[/td][/tr]
# m$ W, p% I N9 ^6 O e[/table]+1
o) {9 T+ N6 t3 p
' U. `7 b: X' N2 _, L$ Q8 U
% d0 X5 h0 |, ^$ b/ h1 O |