下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。" _5 r( q4 O( X7 } c
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件$ p/ B! `# l2 F0 h/ F
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)1 D4 r% _4 _5 [9 W0 |
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
/ E% w& g2 N# G7 b7 ~$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();& p+ F0 g! i0 k6 j+ X7 {7 i
# i- I5 q: k( Q; p; s 或者1 \1 l P9 Z1 d6 q
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();& y0 @' K( L: I8 y( Y% _4 b
: `/ L$ ?2 y; u- }2 {$ z/ q: g+ g
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
. w8 _/ I! n& o4 p$model->query('select * from user where id=%d and status=%s',$id,$status);8 @/ o6 o+ v3 b
/ c, z5 M5 N5 h8 v2 \3 v或者
/ W7 e2 {# [. y' D* U$model->query('select * from user where id=%d and status=%s',array($id,$status));
: M- n0 f, q% `* o
1 J z- E* X+ Q' \6 {5 ]+ ? 原因:
; f7 ~8 Y9 F& o, uThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
1 M, b$ D' b7 N) r; U/ a) A( e原函数:. y, t, m! ?+ ]8 P. N( C
protected function parseSql($sql,$parse) {
, V2 B3 F/ C2 g3 ~. U // 分析表达式
i; x- F5 X2 l9 C if(true === $parse) {
9 I& x. V3 a, N5 J# } $options = $this->_parseOptions();
5 D9 |. A4 t( O G7 N. x! }3 r $sql = $this->db->parseSql($sql,$options);" h3 M P, `8 b% ~/ E
}elseif(is_array($parse)){ // SQL预处理% {/ y/ K0 Z% u* x
$sql = vsprintf($sql,$parse);
0 I B4 ?4 k/ r+ V }else{: r# A" n( J' u- }% z
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));. z M$ _9 c% }- U n" t
}
2 C" j* P- n$ n3 w $this->db->setModel($this->name);1 B+ n- U- C# @# }( H6 K
return $sql;) f; s4 D% {, ]/ o! o& |; s
}1 U$ y }& N: L2 O: I
+ ]3 @8 P$ X3 n, c
验证漏洞(举例):
6 ?. Z8 C$ @" t& I6 ]请求地址:( R0 X; S5 R+ n' E
http://localhost/Main?id=boo” or 1=”17 d i, g; I0 i; B
或
4 p" L G! }9 u/ S4 Mhttp://localhost/Main?id=boo%22%20or%201=%221% x% a4 b$ Z* @7 H
action代码:
7 T3 ?0 {. }5 c. y9 o$model=M('Peipeidui');. K* h v5 m9 d8 E7 q
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);6 I8 A) j# a- F. n4 `5 k
dump($m);exit;
% X, Z' i. X3 K( a或者
3 O! X1 d3 t7 O5 f1 C- r4 z F$model=M('Peipeidui');: b& J1 `* K2 S% U; B# H' \/ C
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));: [# z, ]* f# }- \
dump($m);exit;
) ]1 O8 v6 H5 D% ?结果:6 B% \' O- T; n Q* h1 I: h
表peipeidui所有数据被列出,SQL注入语句起效.8 ^! o o( v! \
解决办法:4 M! k C [1 m0 r. T+ n
将parseSql函数修改为:, ]5 j4 h# x6 U4 _# D
protected function parseSql($sql,$parse) {. m. g: `; ^" f3 ?0 ?
// 分析表达式
9 r7 H4 u' s4 A8 o6 n if(true === $parse) {
) V6 k5 J a" |3 ?4 n $options = $this->_parseOptions();7 `$ x) K3 p% v) x
$sql = $this->db->parseSql($sql,$options);
* }8 |& U* K5 d+ ^! ]6 i0 F }elseif(is_array($parse)){ // SQL预处理
2 T( R. D5 p4 J$ i4 @ $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
0 g% ~+ h7 N& x: @ $sql = vsprintf($sql,$parse);
$ h; T! v, G. ^$ O9 y }else{
% D( M$ s% g* D$ X $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));1 Z8 F4 _+ j$ k2 ~2 p" _' u
}
- {& U$ |: m2 ^7 f) P# h @5 s $this->db->setModel($this->name);
! {9 u" {' Y- F return $sql;4 m! |$ E+ f7 F ^) h- N% U
}
0 G# }1 ^ S7 G& T8 U1 r, w
% k! ]+ i- b- s3 x总结:
x# |- K' Y }% s/ b$ G6 E0 L5 ?: ]不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
9 e3 k p5 ?. b# X! f0 y# D不建议直接用$_GET,$_POST
# W d9 H, }- F# [$ V. r[/td][/tr]
) S" f: y% Q2 @) o$ [& Z[/table]+1
; W$ C" t- O4 l
. k; O& W' g; m1 `( W. ?6 a- F0 G- C* F6 L1 s; T4 Y' d$ [
|