下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。! ]# w- W( @; R' \7 b+ b# \) s: e' F
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
& u" V" Y8 R) Q5 o" R6 S根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)& I3 @, A+ E) U8 P2 {% }& x
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
1 K- X7 ?+ n* m }$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();6 F" M9 t* v O3 k; z
( V/ `: e* n6 m h! q
或者2 C+ [/ U7 Q4 v8 I, q9 c& P8 A: N
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();' U+ r8 B" \2 B/ l
Y: |# [* ]6 M) @( F
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
: W: e9 b0 t7 n- k$model->query('select * from user where id=%d and status=%s',$id,$status);5 W: g8 X6 n6 _4 s6 c
/ D& h2 B# W6 Y a; `: V3 Z; `# G P# f或者
5 |) D. W4 e) ?2 p! z( P$ e$model->query('select * from user where id=%d and status=%s',array($id,$status));
% C* U8 A, v7 N6 H3 g) x q
9 w4 ]" M9 m6 K/ H, E+ z 原因:
3 G+ }0 K- I# f+ b7 R: LThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.( l' W/ O. y6 n: n+ l; Y- {+ w( @
原函数:
5 g5 K; I. o( `, f6 Rprotected function parseSql($sql,$parse) {* F* U* O2 s/ n( d) U) {% M
// 分析表达式
3 i2 ?8 P3 p j: g2 [# b if(true === $parse) {$ H, ^, K) n- l& ^( g: b
$options = $this->_parseOptions();* E S0 o8 F9 s9 V( ]( L
$sql = $this->db->parseSql($sql,$options);
7 H0 A0 l. H4 {( y$ h }elseif(is_array($parse)){ // SQL预处理7 I- V" {. j/ c7 s
$sql = vsprintf($sql,$parse);5 |( z9 z% T" P
}else{
* }2 c1 l/ q: g& E" ^ $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));4 x# Z6 l) Z. J- d$ X
}' f0 c8 }7 t( \: s
$this->db->setModel($this->name);
4 X* y; d( Z0 j7 H+ B4 ?; {% Y" s return $sql;
! v) u+ t: A3 F& \ }
1 a- O- F. @/ q! X) X: h3 W7 l) G7 u' L& g; o h W
验证漏洞(举例):
* u2 V" i$ N# v' Z6 P' @; o请求地址:! j% j- s. e* X% C6 }
http://localhost/Main?id=boo” or 1=”12 T# f8 x9 i! V% t
或) D6 }' a$ |/ b- f3 L! v% \
http://localhost/Main?id=boo%22%20or%201=%221* |' G# e3 c0 j6 s; u) j
action代码:
( L5 [7 J4 N* ]+ D2 x$model=M('Peipeidui');4 v- X) N- }; J" }
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);4 k7 g6 L8 q% E, ], ~5 H
dump($m);exit;
X6 q( `3 { Y6 O i& Z9 G或者' N# B# ]. y/ G, E T
$model=M('Peipeidui');: O" ~, x8 [, V3 ?
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
( Z: j8 g3 Q( y4 a2 } H. w dump($m);exit;
! S; u2 }: h0 k+ t, d0 ?8 W U结果:0 ?( r, M N- z5 r5 B0 D B
表peipeidui所有数据被列出,SQL注入语句起效.
4 d: \: K! g& K( R# O! t解决办法:! F: _; l1 w3 Q# W$ E B1 A @
将parseSql函数修改为:- \1 N' ~+ k( r" H' | G
protected function parseSql($sql,$parse) {
8 x2 q/ v$ e' Y3 E: b // 分析表达式; p: |# \! R) o7 ^6 d
if(true === $parse) {
% S7 d1 Z0 ^% z3 J' r T $options = $this->_parseOptions();' b1 T' r8 W w2 d3 J
$sql = $this->db->parseSql($sql,$options);$ J; [2 M6 _4 U' ], u
}elseif(is_array($parse)){ // SQL预处理0 G' i7 B1 k1 M( ~! `- l
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
' [4 A' e8 A: I $sql = vsprintf($sql,$parse);
0 R7 U/ {/ _1 u' c% o( b }else{ E8 |7 t0 X5 F: G) ~+ g, j6 H3 M
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
1 O! g( O* R* n; s- w }2 ]& { ]) G8 {, d! p
$this->db->setModel($this->name);
& f9 ?0 B7 X! ~7 V$ o+ {5 \; k& o return $sql;- [' N) c# |# s7 r) W) u# ?% F
}
( J" O/ V! _* j! W' z: W
( Y$ e- \) O7 h$ B3 H+ X1 I总结:( {5 i' t- ^9 l/ j. S+ c! o
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查1 d- X6 Z c4 `+ l
不建议直接用$_GET,$_POST
, p9 T9 Z3 b- @. Y1 L, I% O& F[/td][/tr]
6 g2 ]" a# J0 l3 ?[/table]+1
- `0 u( V8 y+ H9 \6 |
& Q( g& ~! x( H B
! e- i/ m: {8 `8 Z |