下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
- `& k; X7 _) R. Q- |" p) iThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
' C/ L8 P6 n3 m根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)8 J" Z" H5 w( ]: L" F
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
8 ?6 i Y& K% ^& \7 b9 ~$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
# V) R4 a: M r3 O0 h5 q0 j6 P2 Z6 F' D9 L6 V9 V% X
或者& j( n( g$ ~1 f0 m% v
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
# r9 h: n, X* J/ E( x: w" e5 }
" z4 [! @, W+ z ~7 }/ b) c( @ 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
6 N4 R& q2 ? x( l+ u, k$model->query('select * from user where id=%d and status=%s',$id,$status);
- O6 l0 t4 v$ w% r( o: H, Y* S
3 r H/ `6 R& Z& f6 w+ E- h$ i或者/ o, j6 G+ K& I& e3 p
$model->query('select * from user where id=%d and status=%s',array($id,$status));) w2 Y. P/ n- _7 d& z) r+ ~0 w- R
3 a/ E/ w+ j; p1 A: k 原因: x0 v9 d2 R% J0 T; b" q
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
0 c3 u( U. J8 ~/ e原函数:5 s. P0 `/ U ~! F9 j
protected function parseSql($sql,$parse) {
" D2 o: s# Y3 l! b) t // 分析表达式
) ]8 z& {+ s6 [ if(true === $parse) {0 p) N- Q3 G: a( x* }
$options = $this->_parseOptions();
5 P) g' Y8 I3 D% j! K' n+ k N $sql = $this->db->parseSql($sql,$options);
. }% n8 E' P! K* z7 |, j3 L8 V+ W }elseif(is_array($parse)){ // SQL预处理4 t0 ^2 b }+ F, ? u- a. F
$sql = vsprintf($sql,$parse);/ [5 A' n( z+ s2 E% C& y4 K
}else{ ~7 J t4 ]9 f9 d% F0 g& _
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));, s# w- R* A3 x
}
$ R% ~" r" r& }0 n $this->db->setModel($this->name);+ N, Q: D# [- f$ T- g1 h
return $sql;) p- r) y( w# R. L2 u
}6 q3 v( y! z$ J: p
/ C8 y0 z3 e8 t$ ~- T( ?
验证漏洞(举例):8 L# b% ] s$ K$ M. l3 f; B" s
请求地址:
7 p% a5 B4 p" Xhttp://localhost/Main?id=boo” or 1=”1
4 F: j7 b! h9 M! s- E% B- f或
# U B; p+ G: g1 N- ~http://localhost/Main?id=boo%22%20or%201=%2212 X0 ~+ |; k* ]- O) q: e% x1 o
action代码:
5 y" A6 {* c, V* O2 r$model=M('Peipeidui');
+ _' |' N' A. q3 S& m3 P $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
; \% \6 }9 F g f2 s dump($m);exit;
: L4 t+ z# Y9 N1 Y或者2 x0 x. m0 P3 V8 h$ v% W0 ?# f
$model=M('Peipeidui');
! b9 a# T( n+ K o w $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
; V. u1 Z# ]5 F dump($m);exit;5 o% g: o6 H4 A2 F% X9 S) [
结果:
. t7 I; j" ]9 T' K+ K% t9 {1 K. `- Q表peipeidui所有数据被列出,SQL注入语句起效.
8 R7 ?2 D8 ~5 T. M7 K; h解决办法:
) U1 Y9 W4 ~0 i; G; ?& z" T" C4 R/ ?: D将parseSql函数修改为:
$ H/ w) ~* P+ j/ _; H1 u' dprotected function parseSql($sql,$parse) {3 }5 H) n/ H# ?) L% [) P& r! C) ]
// 分析表达式
1 Z$ h* u6 C' k! [ if(true === $parse) {
% K2 B$ N3 Y$ k5 [' s2 L. e $options = $this->_parseOptions();
* ]2 m, L' r& r: _! C $sql = $this->db->parseSql($sql,$options);
# n4 n+ A! `: j8 c. v. I* C" c }elseif(is_array($parse)){ // SQL预处理( n, K3 @# K5 _! o8 J$ M7 l2 k
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码8 u6 |. [ q% `6 |5 `' q2 }
$sql = vsprintf($sql,$parse); j/ F5 b7 R; Q1 d
}else{
8 n. ?( f+ p3 h. }" ?" d $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
* C6 g3 Z6 Q8 S% r0 r1 y% Q }, C9 G3 G+ S( |1 i& Y4 e* A
$this->db->setModel($this->name);
* E4 r; r7 Z& @" x" D return $sql;
/ o) y5 s) V. R) u8 \" V }* n/ |: }9 @, {/ D% E8 Y
# h- m4 G6 M$ j) A5 M* U7 x
总结:
6 W: e- J$ j! W+ F! d" Y0 K不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
3 k/ } J! I& P4 q3 U9 \不建议直接用$_GET,$_POST6 Z7 G8 g! z5 e ]: `& s) S5 c
[/td][/tr]
& L; _# J: U) f1 S[/table]+1$ k6 H3 y! n9 M8 K, C& [
2 [ i, `; W7 i `
) ?' S( c/ |9 x7 ?# z5 U- F |