下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。5 L" |, ^; H) o* J8 Y
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件/ v& O }6 C! s* _
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)" r8 E1 I0 ^" F' ^0 w
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:2 {5 i [" J1 T: E2 \8 n
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
6 s7 E5 d/ Z% ~2 D: K9 d- V- S. q! {! W, Y) F$ A
或者
`9 t5 Y+ s' @) K6 x4 \/ C T$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();" x+ l6 M2 E# s, e7 X6 D
- s% N# h. c* | 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
: X g) S4 a3 }0 ]$model->query('select * from user where id=%d and status=%s',$id,$status);
% ?5 ~2 m" Q; {1 ?. ^9 F3 e' h l O, C% E
或者
! _, E6 [4 \/ ^$model->query('select * from user where id=%d and status=%s',array($id,$status));
2 E" i* V/ y. ?" t: u# X I2 _ h. s! A; D% d
原因:: H0 i! ^( r, h Z+ G
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
) F# ~# y5 [7 R; l- ~原函数:4 y7 F6 _: E9 y# K2 _# \
protected function parseSql($sql,$parse) {
, N; Q$ E* D% R( l: o0 T // 分析表达式
3 x2 V- Z. y7 s1 a1 ^' n4 Y if(true === $parse) {* R+ F, y3 n- k1 K' f
$options = $this->_parseOptions();
+ y% g9 m' g) T" r $sql = $this->db->parseSql($sql,$options);8 I; t! F ~' D6 r1 ~
}elseif(is_array($parse)){ // SQL预处理1 ^# q! r _4 ]) D
$sql = vsprintf($sql,$parse);
8 m$ c" {* @, v" H" h }else{
2 C/ Z, }6 ]+ ]" N* i* s $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));7 b2 A) o) K! Q
}7 o; B, k1 V; u+ ]1 p
$this->db->setModel($this->name);
) m* b# z6 n/ b& Q6 h. W0 K) h$ _5 @ return $sql;
: x3 T& ]' k8 h. b }
& g/ u) _# i4 {, ^7 U2 }0 |7 ~9 L5 o, r; ]. L! e0 }
验证漏洞(举例):
* Y) `! o: a' V, f; I请求地址:3 @" L8 r8 u S( n: j
http://localhost/Main?id=boo” or 1=”1
* N1 J6 @3 E$ u7 ~3 H' D8 @或
( S: K4 Q/ `. X2 P# z( j" Jhttp://localhost/Main?id=boo%22%20or%201=%221
p% A. q4 W, s8 e5 @/ t/ [action代码:$ k2 ?+ B+ |( w* S9 ~9 k
$model=M('Peipeidui');0 H4 `$ }& c8 L* u S( {1 U3 e5 @& e
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
8 e" S, @& y5 w( b; J/ I dump($m);exit;% Z- k5 i; D6 L$ N( A. k
或者4 w1 d% W* A' e- `( `+ p- w/ c
$model=M('Peipeidui');+ W4 X0 k! U$ u
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
7 s" p v' N( A* } dump($m);exit;" |5 M% \* Q. i* r6 ?, `
结果:# @! o2 s) v$ d0 b7 p0 I. W
表peipeidui所有数据被列出,SQL注入语句起效.9 s- M! }2 |/ `3 x
解决办法:( g5 U9 ^& k5 c* f( T
将parseSql函数修改为:* R$ P3 g. Q. _, p% G+ g
protected function parseSql($sql,$parse) {
0 D9 g: v# k& o7 E: I4 F // 分析表达式. F& a4 [; L0 _3 M" M! `1 z
if(true === $parse) {( k, f5 P" A; `% P- C5 Q" ?8 a
$options = $this->_parseOptions();
8 l& C$ {* m+ L9 ] $sql = $this->db->parseSql($sql,$options);) U7 x8 D! j. y& M; q+ K
}elseif(is_array($parse)){ // SQL预处理- I* c' ~/ t, c2 l
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
9 @# t m* y2 Y9 Q $sql = vsprintf($sql,$parse);
; p5 {$ D, f% D }else{
' ]2 V( ?6 g v1 w$ \ $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));6 y, P3 V4 u, p0 A9 ^
}5 t! h c7 ]/ b* o2 {0 d
$this->db->setModel($this->name);5 \. P: ]5 u6 O' q8 G( Z$ _' k
return $sql;/ |$ ^! G) O4 @0 F. E
}1 Y5 E D8 F6 s3 e3 S2 v
6 V: c3 m& g/ h m$ ~/ A( ^总结:; v. Q/ @- D) f
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查! R, c8 _% Q, L3 I: v6 H/ t8 I6 e
不建议直接用$_GET,$_POST
$ p1 ^( T Q0 f1 q[/td][/tr] y% N: t) Q$ A) @4 r9 P9 l- G
[/table]+1* Y4 x& m$ G, A+ z
6 C' l3 F/ E5 H: c; u& i: y$ j* i j3 K' [6 F
|