下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
5 x1 n1 A- q" V* C0 s5 x# HThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件- L! e1 q$ [* @9 b9 }1 p2 ^$ f8 W
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
. r+ p/ U# H4 I3 W+ g, g使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:+ X; ]3 O. G& ]! x' l% Y) c
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
+ f* L. g2 T- s) h6 u2 U+ t% t- K8 ]7 L) B! h' U( k* K7 o; K
或者
" n! R' [. P# O* H. n$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
1 l" n7 W4 A5 o" b, g5 @: }$ M1 ~+ _% D# X9 K) n( p3 H0 @- C
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
( E9 H" n! f" j O$model->query('select * from user where id=%d and status=%s',$id,$status);9 h# p9 t( d2 b9 [
) f6 e% Z& d3 J或者$ c& ~- g r0 i/ ]/ s
$model->query('select * from user where id=%d and status=%s',array($id,$status));! [0 ?" {1 o3 L, `, W
. l* H/ N& l: J, N" W 原因:
$ V8 w* I8 }1 `1 Q. G9 {6 dThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.0 Q8 M. ?# W4 x# I- ]
原函数:# v+ _: d* t& K8 n& Z6 T7 @: s8 Y5 d
protected function parseSql($sql,$parse) {
; p/ ?- b5 Q0 p: z7 e+ B$ c // 分析表达式
8 N, Z. ?$ ]) J$ k* [) x+ t if(true === $parse) {1 g! h2 a2 ]; z/ m( Z
$options = $this->_parseOptions();
+ E h+ T8 T6 ]. @& J6 ^% l9 [ $sql = $this->db->parseSql($sql,$options);5 B/ q: T" [" }0 I* @5 O
}elseif(is_array($parse)){ // SQL预处理1 q* @; H' U- A/ _
$sql = vsprintf($sql,$parse);
+ t8 y" A, T- T, a6 `6 R }else{1 I% [0 G; |& k' q4 Z; \' k
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
# q/ Y( [- q7 R8 f: a4 r' ? }( Q3 P" k; O. H! ^
$this->db->setModel($this->name);) g1 b ^6 T! Y8 Q) I( ` y
return $sql;0 R6 N6 t8 M, }" a3 s6 W# V
}
6 r/ l6 l4 H! P& G' R: {5 X* I/ B
& R+ }: G4 e3 s/ Y验证漏洞(举例):
4 R. N! B! F1 d: R: F4 k7 s请求地址:/ v) j0 M) G5 e
http://localhost/Main?id=boo” or 1=”1
6 o& L1 n4 I4 \或; r5 N( s% k3 L
http://localhost/Main?id=boo%22%20or%201=%221
1 I1 E" V3 p* W9 k" j& daction代码:9 d7 U- q3 y+ t8 n" F( g2 [
$model=M('Peipeidui');
1 b3 w$ C& h; t, K $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
; n6 m, Z3 R) K dump($m);exit;
* }, j. P/ |1 N7 E P5 H或者
# E' m) k1 l0 a! s$model=M('Peipeidui');9 b5 ` j* A( H- l
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
; Q, n5 W: |, [! @' m! h# n( d dump($m);exit;
/ b( n# A; T) y0 D, | |' A结果:
2 @* m8 j9 a E! g表peipeidui所有数据被列出,SQL注入语句起效.* z: P- }; t H0 Q6 D
解决办法:) c7 k3 v; q6 ]
将parseSql函数修改为:
( g# K$ t' E& \protected function parseSql($sql,$parse) {* J; N( I" Q: u5 M& L6 ^9 G
// 分析表达式
) L" k! J1 K- w* l if(true === $parse) {
' \6 `. ?) P6 L3 H* R5 m $options = $this->_parseOptions();
" D0 V8 z' h' @0 z $sql = $this->db->parseSql($sql,$options);
: e3 a9 p: \; m7 Z a }elseif(is_array($parse)){ // SQL预处理
- |0 t9 _' X" l. L $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码5 r# \0 j7 v; y' a& Z& E
$sql = vsprintf($sql,$parse);% x# |4 L1 z" c P# T
}else{
3 [, N3 V$ o# U5 g $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
( I: L; ~5 Y( f$ r' u }" y7 o- R3 v7 J' C9 ]2 e2 b; Z, b |
$this->db->setModel($this->name);
$ j* M" {% n/ N1 _ return $sql;
0 x# Y% `9 i4 G; H% t. ^ i! {$ Z, w E4 @ }
9 F+ X8 b# H1 M) x2 \7 D/ r$ ^. H2 G, l! r+ z, _
总结:
7 s% y" a* u0 G; Y& K# R) A( f不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
I% ?- T% V5 e: A/ @8 _' `- O8 E不建议直接用$_GET,$_POST& ]+ d& y8 z1 L" O
[/td][/tr]2 G* }6 s) X, {* ~& U, Q- T
[/table]+1
; i7 {+ _3 b. x2 {7 \! T
$ T8 f7 r& T" Z' z1 T7 x
# Z( j0 L0 L5 L0 Y: M+ o |