下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
7 I% `5 Y# L/ c. d( h. g S0 VThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件* r, D' T4 Q h* a" I$ |
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
0 t$ R* N& T5 A' C2 s使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:3 z5 R" i/ L% h/ C0 A1 T
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
9 {, h8 \, P; x5 k2 {
_3 u t6 g8 \2 @3 V* |6 {. m9 q5 Y5 W 或者7 J) {1 |* a) w3 }: a1 ~% v
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();1 }; h8 q* U5 J. d6 K# `
3 }1 S3 y; D) f1 g" p6 b! { G
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
# _( w# d& D9 L) v# u, a" e" M$model->query('select * from user where id=%d and status=%s',$id,$status);4 w9 ~+ f7 O% f$ b5 O% c
; M3 ? A4 e+ d4 t i
或者
0 @# ?. y1 a5 Q9 |! ?* z4 S& ?. I$model->query('select * from user where id=%d and status=%s',array($id,$status));% C0 s) a8 k2 T% R. r( E9 R3 s6 H
# N: K% ~ G, x! [0 Q 原因:
) q) M: B, A" {5 w, {$ V+ _6 jThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
; R0 C* t9 {, {, L原函数:
' u4 D+ ^; q7 Yprotected function parseSql($sql,$parse) {
* A* v/ e+ H5 d; r* w* | // 分析表达式
$ N7 G, z$ q9 x' Y3 V# A if(true === $parse) {
3 k2 @4 ] ~) Q9 n2 s $options = $this->_parseOptions();+ o4 a0 \ \- T) X+ p0 g1 q
$sql = $this->db->parseSql($sql,$options);
4 l1 f3 z+ r: t+ K+ r }elseif(is_array($parse)){ // SQL预处理
8 A6 _ o5 `" v/ z1 }/ p+ n" O! P $sql = vsprintf($sql,$parse);
% n0 l7 j# h1 A+ l0 C% ~ }else{5 h% ?. K1 y9 V% c3 [( ^
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
( E$ s) @' j D% H# u) T. H }
% p3 a& `6 r7 _ $this->db->setModel($this->name);& g" `1 _) Q; d& h' z7 V3 W/ k
return $sql;7 Z5 G0 A. B P9 e% P9 b
}
9 U: g8 w$ J) I* b. E1 @) E9 C" M# z" H( j# _ g
验证漏洞(举例):0 t# v% j( [' u+ e( s5 ]+ R
请求地址:
) B* L; v" K2 Fhttp://localhost/Main?id=boo” or 1=”1
- Z5 ^6 x# W3 i8 s" _或3 y4 ]+ d) N% _( |
http://localhost/Main?id=boo%22%20or%201=%2219 R; I. P6 Y6 V$ r. `7 [8 i3 V$ V( x: j
action代码:
Q8 N7 l& z+ h: b0 y$model=M('Peipeidui');( a2 E& m A! @2 G' Z
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
) x9 m' f0 W& G& M dump($m);exit;. x8 j/ q* h: J- Z
或者
' \" K9 q; s- T4 F1 T$model=M('Peipeidui');
! B3 F1 b1 d3 K; E9 E7 u $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
% o; t" s4 c: z: V' p dump($m);exit;2 o! e Q8 C5 q5 K; t% q
结果:% j; J: w [3 O
表peipeidui所有数据被列出,SQL注入语句起效.
, n4 ?; C( Q% Z/ f, U0 }解决办法:- s: l' {$ x0 x. v- ?+ q2 @
将parseSql函数修改为:
9 d; v3 l* ]- k6 f6 L7 a7 Uprotected function parseSql($sql,$parse) {
8 F" v# ]/ U/ A2 q // 分析表达式
) t, v( K: r" E6 K" P if(true === $parse) {' Y5 e2 D) q7 W' }. a0 k
$options = $this->_parseOptions();
1 B1 i" S, z3 R$ C d N $sql = $this->db->parseSql($sql,$options);
9 k, m8 f9 R9 _. o/ ?/ Z }elseif(is_array($parse)){ // SQL预处理
% O8 K# }: s3 A/ u- t $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
% U9 n3 o% O/ V# d: D% Y; ` $sql = vsprintf($sql,$parse);
9 ]# A, ~1 k& x i' W! p& ?! ]# F }else{
" g( e. C( Y) Y9 g% s& |" n $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));) r* P. y$ B+ Q! q7 I7 M2 I4 [
}
8 n! o) }! Y9 P# z( v) s6 V7 S $this->db->setModel($this->name);7 y3 n x$ |; X, K5 _
return $sql;
# }! r. N4 O' b }
+ I" D4 L) W8 F6 l. Z2 C8 W! t
总结:
( _* I; ?% X# N* {6 z不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
a* Q) h$ T9 l不建议直接用$_GET,$_POST |/ p. K1 J% k( _$ V
[/td][/tr]& Y* _4 k4 X% ~% r6 R" t
[/table]+18 Y) f6 _" X% h! ^& G+ C ]2 w
. m) u6 y& Z2 V7 v; z' ~
" U/ G% [( A! O+ X' _* R |