下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
$ m0 {' {* x, b M( @ P0 LThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件" q2 a j; }4 O/ A5 R6 O
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)5 s6 x9 a+ N; o5 }2 J7 G: a1 F7 w
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:% P, w5 V; W# z& K" S
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();3 a- x3 J7 B& U
; J0 @0 h* _, V
或者
3 i: H/ h7 D: ?6 }8 ~% \- D$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();8 {/ S! T% f) t7 U9 ^
9 D" Z# d1 k$ C: J0 v( C4 y4 y
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):9 z/ v/ \6 W r! X/ l
$model->query('select * from user where id=%d and status=%s',$id,$status);0 @8 m4 Z3 a; ~) I2 G) G& A% V
0 F1 E) \6 }9 x+ j或者! c$ M7 v i; q
$model->query('select * from user where id=%d and status=%s',array($id,$status));9 M1 V7 K7 F2 l3 z$ X
4 m* R2 I. e4 E$ b! N: {
原因:
- n6 g M* _% Y3 V+ r' D! d( _ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
3 ^- Y# [- n0 s& L* q w7 `原函数:
, J) d, ~! a6 v+ `9 u/ Q6 Rprotected function parseSql($sql,$parse) {
. v' o9 C* J" ^3 l4 r // 分析表达式
8 Z8 h/ p+ i+ {& C" g: A& n9 B if(true === $parse) {" u8 n9 Q, v/ X9 G, G0 i
$options = $this->_parseOptions();2 S5 D1 [+ X, m& j* b; n. X
$sql = $this->db->parseSql($sql,$options);
- f1 g+ q, [/ {6 ~ }elseif(is_array($parse)){ // SQL预处理
3 {; J( q: `. A1 z $sql = vsprintf($sql,$parse);/ q, k" X7 p' p$ W- o6 T: P: E. N
}else{
) U& G; m) t% N! i% U5 e% { r $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
1 B: p( D( E' Z/ ? }
; }3 K( F7 ^ u% h) y/ C $this->db->setModel($this->name);1 z0 b) h8 Q7 s+ |% `5 L
return $sql;) t3 O- f" h* y9 ^# `
}
/ c$ J( `& [+ t8 {
% B' a5 D; V/ P3 L: ]验证漏洞(举例):- k H: _1 h! B
请求地址:1 [- M" M' ]' R" j; |& l
http://localhost/Main?id=boo” or 1=”15 g' J+ S8 x- K% d3 J1 F& K3 c
或
! Q3 b1 ]& Z4 {8 J6 V5 qhttp://localhost/Main?id=boo%22%20or%201=%221
3 u- z- n/ B9 F6 b9 m9 t) daction代码:: N, H2 |& `; @2 n' @
$model=M('Peipeidui');6 o& Y: I6 `" D( j _# q
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
0 \# W @. H- {- N9 a& c dump($m);exit;9 r; ~5 q* ?2 I4 A6 o, r
或者& G7 @6 G0 o" u2 @- W4 F; A O
$model=M('Peipeidui');. e/ k' P% G4 J" D3 }: o' ?
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
2 @' K3 J) X5 _0 I! @; O1 B dump($m);exit;
: d; O/ z% q9 X结果:
% o! {4 R9 H( ~ f* B' i表peipeidui所有数据被列出,SQL注入语句起效./ T' z6 W) w) `% H \8 p, N) E
解决办法:$ z( D3 y9 J, o9 b
将parseSql函数修改为:- O4 H7 r1 H" X, a+ D2 s' e N+ N
protected function parseSql($sql,$parse) {
3 Q' x9 P/ U% `4 d2 Z4 K // 分析表达式7 B0 r( O$ {' \: D# g' p4 l
if(true === $parse) {
4 u& S7 ^; l2 k% D $options = $this->_parseOptions();
& p0 }) B2 |; E $sql = $this->db->parseSql($sql,$options);( ]' p/ W4 @. w
}elseif(is_array($parse)){ // SQL预处理6 D- m. k8 p& s. S9 x
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码, }1 D& h( @& u
$sql = vsprintf($sql,$parse);9 f% T( w0 u, V8 O
}else{
8 C" y( A* q. ]/ ` $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));5 z5 g) y" ?: M& k* T4 [
}
+ m! \( m/ k* `+ t" d: }! @; G $this->db->setModel($this->name);0 U9 }7 h4 D( a! k
return $sql;' j0 O$ O; O7 J% D
}4 O, o% a4 H$ C+ x
4 `- s9 U" s" T; ~总结:
) T% E1 ]6 u. K! q3 K1 p7 O# ]不要过分依赖TP的底层SQL过滤,程序员要做好安全检查8 w7 \' Y" j- G
不建议直接用$_GET,$_POST
' T3 n$ [$ a% s- i[/td][/tr]
% ?+ J# q; [: b' @ e, \[/table]+1: v" R! h& m8 J3 P! X+ G( T
4 F) S. V, k, d6 c1 s4 ~
. {3 ^, D+ j7 \% x. i2 u. Y |