下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
) F3 h: V P! K4 J* r/ IThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
( g# I0 c8 Y$ x/ @; ` g根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
: f% |' t) n K! b# c9 ]! m使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
1 a* d# i- k( f. M, z3 D7 ^$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
6 }$ v" t) p5 `+ x: {9 l1 y% e; c9 R, r* Y" m. J
或者
* |$ Z! K) b& Q; s. M$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
( N- ]0 O7 p- i! k" I( v
8 D H$ R# n' Q6 {0 X 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
2 e$ L3 }, ^8 F/ T+ Y2 j$model->query('select * from user where id=%d and status=%s',$id,$status);
- n2 E3 L- S2 S0 p+ I3 a: A9 J# Y6 C* b4 K" i
或者0 E" s; e+ `7 L3 ]6 J; l" g
$model->query('select * from user where id=%d and status=%s',array($id,$status));+ ]$ ^1 k0 [7 e. h
B: Q1 }0 {: p1 z1 h
原因:3 r" J+ w9 w2 l% c- `3 o' E, N
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.& B; h. y+ r/ @; E& K8 i% q
原函数:
1 L$ t: J. n' j; f0 mprotected function parseSql($sql,$parse) {
; w0 A2 c/ z4 R N& z // 分析表达式
/ j3 k+ M/ v3 e, S7 b) l$ | if(true === $parse) {6 w6 h2 B: ^1 J. ?7 M* U# V( \
$options = $this->_parseOptions();- x8 Z' F7 @- u4 X7 f: ^" J! x. g
$sql = $this->db->parseSql($sql,$options);# Z( _! d R8 o9 c
}elseif(is_array($parse)){ // SQL预处理: k j- B' _% c# U% k
$sql = vsprintf($sql,$parse);/ _ f: F# h, ]- r$ p9 Y
}else{7 g7 H4 t) _9 q, X# p
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));( g& W" `3 X5 }/ Y7 v% C6 t
}
u, i* E. K# u8 u& O) l# { $this->db->setModel($this->name);# {9 W8 s' ?9 G7 Z5 v6 ]
return $sql; V# p+ F K( o! B' ~
}
# L5 L+ e* r* u
1 t. u* f. O& n0 U( I) {验证漏洞(举例): g% ^; [( g- ?, K% t
请求地址:7 h& \$ L& j& m
http://localhost/Main?id=boo” or 1=”1* a; J v) k6 T; c, V6 v2 P
或
3 _8 {& M3 y6 q, J# ?http://localhost/Main?id=boo%22%20or%201=%2216 @7 `- G8 R. `0 L/ `. J( L
action代码:
5 a/ n7 W1 @( e5 C! B( D& {5 ~ ~$model=M('Peipeidui');6 D" r6 b- H. m6 a. O: @; z
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);+ c. T. [$ ?& x3 }' J" N
dump($m);exit;, x( m. }6 N5 S2 Z0 L( u
或者8 B6 D0 H+ u$ y: F. p; j
$model=M('Peipeidui');( k3 G4 W; x: _! l3 Y
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
6 X |5 N) G) x5 B }. j* j dump($m);exit;/ V1 K+ R" w6 k' V
结果:# r) B0 p' N. x. V
表peipeidui所有数据被列出,SQL注入语句起效.
) B+ g/ j9 A. z; w! @解决办法:: _9 r! C {1 [/ }2 R1 u
将parseSql函数修改为:* J) x$ ~2 B2 ~. C9 ~: ~9 Q
protected function parseSql($sql,$parse) {
- H U& J% C* m' D/ n // 分析表达式
5 |$ V5 O* r* b, k if(true === $parse) {, C9 [9 ]) c) M6 p' g
$options = $this->_parseOptions();* Z1 K! C" u/ C( {
$sql = $this->db->parseSql($sql,$options);# [+ K! R4 S- w1 |' L
}elseif(is_array($parse)){ // SQL预处理9 Z6 m9 ]* M. k4 r
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码5 _9 j% b$ a% w$ O' o; b4 C
$sql = vsprintf($sql,$parse);$ X7 A0 I7 _* ?. {0 d3 P: D
}else{
* u8 M6 K# F4 Z4 p7 S/ D( g $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));& e3 d f! X4 V6 K; L r
}
( n! ] P5 m* \$ G: n3 y( ? $this->db->setModel($this->name);
$ `$ ?$ a7 c2 z- C% D& g return $sql;; i. N& \- T5 U2 O+ J
}# j6 b) W" D o$ n) A! h1 s+ t) q
7 C/ G+ Q# K" G# w# k; E
总结:, z3 J$ l3 H7 i+ V# K+ W* r9 h
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
2 T# V6 G% j: g; v" q- P$ H不建议直接用$_GET,$_POST5 G6 t( N! e( O+ o* J. [) H6 G
[/td][/tr]3 A1 i/ ?+ P% M3 Z9 u
[/table]+1
* S: C8 O4 g0 ]. Z% e' m, l" t( J; K0 Z9 ?/ i
( A; I. u" d/ Y& V# v# C1 h
|