下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。4 v7 U. L2 |: A, S1 M6 d: z
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件) u4 X6 X8 L+ g0 q1 \
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
: S5 ~2 ^* y: r i! _) }, z. H使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
, ?) C2 `5 r9 [' y; Z. m8 C$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
) b6 z* m6 i( f/ D. s
# J! X @" e1 t! \3 u* A: M7 k 或者
; R* t. e4 k# l1 F" v- E$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
/ ~& ~1 [! L6 q+ b9 B! z! m$ O6 E) K3 v% z' h- r/ a o: \) I8 [
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
9 J& K4 m5 v$ _ W$model->query('select * from user where id=%d and status=%s',$id,$status);# z* X0 d$ Z3 C% [* @. F) Z
0 R; K. n7 H. }) Z或者) q; S, d) y7 @
$model->query('select * from user where id=%d and status=%s',array($id,$status));4 u0 C& G/ h8 n7 x
3 W. |$ b+ F0 \4 h+ Q7 M9 C 原因:
. P# T8 Y( ^( B. hThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
. v- k, Z: {# M d/ b; O$ W原函数:1 t/ e J5 x$ Q! c6 l' Q
protected function parseSql($sql,$parse) {
, ~2 b; j K( F5 P4 T // 分析表达式
0 T5 q8 t+ d7 q: p8 X, N if(true === $parse) {
1 x- G7 E5 T! h: s $options = $this->_parseOptions();
( w( A, _/ C9 A $sql = $this->db->parseSql($sql,$options);
% H# A, U3 x& [" S }elseif(is_array($parse)){ // SQL预处理 a" e% K! ? J$ e: Y: u
$sql = vsprintf($sql,$parse);2 O% q* x7 S- Y: x2 m
}else{
, k. B1 U* p6 W: X5 ~! ^ o $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX'))); z" V$ s. s4 p1 y [$ P: |
}
5 [) Y ^0 T$ N& I M* s $this->db->setModel($this->name);% k. p& t3 o* H: k9 S
return $sql;
1 L6 V8 ^* o' s- G9 R }
; X( Z# R3 o( s" T/ @, R% n5 Z+ @7 Y, n7 H( N
验证漏洞(举例):5 p! Q( T R; ~! Q
请求地址:) Z: q& H- G) d) ^5 `; {
http://localhost/Main?id=boo” or 1=”1* C+ e, {: W v' Z
或0 s6 ^1 t% U6 Y7 b4 ], X, M% P5 O
http://localhost/Main?id=boo%22%20or%201=%221
+ p6 I* E+ A/ h" u8 W/ V raction代码:
( `0 C6 v" w( M9 h( y' E$model=M('Peipeidui');2 a9 t9 M# C" b! z9 q$ s
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
" _) U% E; P; a7 A2 @) O* u dump($m);exit;
, o; A% M/ v( S6 z) U或者
2 ^3 A7 d. o* s8 y. l# M$model=M('Peipeidui');
, F8 ?- f7 d8 l7 h* ` $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
; ]& i9 o5 b% [- { dump($m);exit;$ P( K+ p! H, N, d3 Q
结果:1 ^% g: {* ] f
表peipeidui所有数据被列出,SQL注入语句起效.. N) z: e; R) U0 K
解决办法:
- U. p; G8 ~6 ^- Q% F, C0 t0 B4 B3 i将parseSql函数修改为:- t* m8 o, v5 c! _
protected function parseSql($sql,$parse) {
9 O7 u. p5 g; _ // 分析表达式5 S; J: O0 j! E( \ l# I2 r
if(true === $parse) {4 K- a! A" b- M! H5 a3 k; ?4 W9 {6 u
$options = $this->_parseOptions();% o. I3 f5 y$ X* X* Z* u
$sql = $this->db->parseSql($sql,$options);1 }7 ?& r/ n' {7 P) X9 A
}elseif(is_array($parse)){ // SQL预处理
+ Y( j6 ~: S% y7 ~* b $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码! Q1 q. T9 F$ Y2 K4 X7 R' k
$sql = vsprintf($sql,$parse);
. ]5 e: O! {- { i+ q* @8 ` }else{# b4 I4 d# F3 T0 X
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
4 @9 F; b* }' }* n }
v/ S8 r+ X! y" a# I) y) i# r& \$ N $this->db->setModel($this->name);
, y. x) G0 |8 E4 \ return $sql;- O1 X1 g" Q; M, G8 X
}
' b, ^+ ~' H: w; M5 H
; n# F# S* Z' E/ ^% B% Z0 k% m总结:
7 u1 Z, F5 U) I不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
, u' Q+ z9 R2 O& E$ E4 ~5 M0 q不建议直接用$_GET,$_POST
! |1 N6 ^& e6 Q7 a[/td][/tr]5 B1 o4 E( L- J8 {% ?5 D5 a
[/table]+1! e5 v) y. B2 A$ q
* R1 J! Q) r# J6 R0 v+ p# d+ o
. q1 i' X8 {3 V8 [3 N2 ? |