下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。5 U* v7 A5 h6 A
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
. Z6 }( g7 W3 U. k根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html). M7 M# g" d) \
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:9 L3 E9 `: z) t/ R
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();/ D0 _! @' k+ C/ i" G
; @) k4 u# V+ \& ?' t6 {
或者, z% e& l2 @6 `$ X& J1 G1 J
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
& N- r$ i0 R5 D* s) x# X1 J' g7 \
: o) _3 k9 H% g7 E' V3 ~ 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):: \; \& d+ I4 f4 Z& x9 {- m3 x
$model->query('select * from user where id=%d and status=%s',$id,$status);
3 ~6 b; u4 T7 i; w- m. z
# L, _1 g8 M$ \- t4 h或者
% L# B$ a# I8 p _# ~1 u$model->query('select * from user where id=%d and status=%s',array($id,$status));
8 q9 x" B9 G# z6 R3 H: R ]4 k4 } a4 H. ~: J8 o5 \0 _( ?
原因:" r& X% X0 O/ Y/ W4 T
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
' Y# K6 a& J0 i$ k8 o原函数:3 v7 w/ q c, h- I x
protected function parseSql($sql,$parse) {2 U2 [$ x4 ]' v1 Y7 k# \ L( q
// 分析表达式
; I0 v. X6 R. ~! d9 o n if(true === $parse) {
6 r/ w" I" Y d. c+ ] $options = $this->_parseOptions();
6 n4 R% B: x$ S1 j$ x4 P2 W $sql = $this->db->parseSql($sql,$options);- x. x$ A6 d& @; e% C
}elseif(is_array($parse)){ // SQL预处理
& X* c; D% Z, W; w" M $sql = vsprintf($sql,$parse);
% w0 a c7 |, j# e0 k6 A% b" ~ }else{
% Q$ I, s) T: n B $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));. ^* c `, g3 l8 x N
}! g6 V4 P( T7 H/ ~- Y
$this->db->setModel($this->name); Q- G0 `" ^1 |) u0 H
return $sql;
0 S1 G: p% k! {6 ]5 {' t }
2 p" c2 r* i# u8 P5 m# X" g* h8 P* z
验证漏洞(举例):0 [% e) H: ^" \' v
请求地址:' m2 w9 k% F9 V/ }
http://localhost/Main?id=boo” or 1=”1
3 p/ R" U8 T* n9 }$ e O: a4 C4 S0 I或2 y/ v7 J6 P6 W9 ~: @$ S
http://localhost/Main?id=boo%22%20or%201=%221( R9 A; `& |1 }# b6 B5 ?
action代码:
; `7 |0 |( T/ B% m8 ?$model=M('Peipeidui');" k; R( X8 [% m
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);, U9 k0 k+ o' D% d, G# F* U
dump($m);exit;
. t( U7 J4 H( P7 j4 ^ e或者
7 Q5 @8 E/ G' ~- j8 E$model=M('Peipeidui');5 }) D% h' Z) h& S; J6 h
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
d7 H4 W0 X) f1 w0 k dump($m);exit;7 N6 {2 a2 C1 C6 }% f4 L! q
结果:. ~- ^+ U& r6 {3 ]. G: ^: S* v
表peipeidui所有数据被列出,SQL注入语句起效.
( X" e" W0 h) I& g7 ~解决办法:( ~$ v, ~! n* z7 {* K! `; _: O
将parseSql函数修改为:+ J/ T* ?6 l: o
protected function parseSql($sql,$parse) {
) t4 _+ M6 h: I$ y // 分析表达式/ z0 c+ M3 c! a a: l1 l* e4 l# y
if(true === $parse) {
: R+ t1 ~2 P; B' R8 @6 W $options = $this->_parseOptions();
% M& p ?2 D. x2 B7 p* F* d8 S $sql = $this->db->parseSql($sql,$options);! t0 G8 F2 ]9 h( a6 I4 g- n" ?
}elseif(is_array($parse)){ // SQL预处理, s4 B( U9 O6 Y/ W) y& d
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
2 \; Y5 `+ \. W) B0 a $sql = vsprintf($sql,$parse);( a: @) q1 Q) L8 _9 d, d# m: A
}else{9 C% l' D# P7 X
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
1 ~, X6 v3 y8 B }
, F+ K+ J# V* R) B4 }0 k/ r$ M4 A $this->db->setModel($this->name);5 O( e# u; o* `$ N
return $sql;
3 _/ j7 a9 s6 O3 i: b/ k }1 n! k/ ?9 x( @+ z
# ?0 I4 `# E* H总结:
0 \1 M9 {5 r# I% U不要过分依赖TP的底层SQL过滤,程序员要做好安全检查, h k! T" d) j; ?% N
不建议直接用$_GET,$_POST
5 J& X, @6 N, A/ ~ v- o0 J7 P[/td][/tr]
9 x1 d( W9 j: o* d9 S0 F[/table]+1
+ d8 N+ e, p& ]# o3 o0 \, }# A% r% g, s7 O- e
! N4 ^) m* u( t* a
|