下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
, E( ?. {: J6 ~6 }1 h" rThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
" k/ m# r* z4 M; V" H# L$ d p根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)' c; @* G) z; c! g
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
" T% R$ s8 L- h8 c: @8 E. ]! d4 G" W$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
) l- q$ H6 l5 p0 `) ?/ K( W" y. z( I
或者/ S, Q! l m, f) N5 u! i
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();, w |2 U2 o3 E$ ~ n9 B" N' E* u
- M( K5 B5 z5 l( m 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):$ I+ C0 s* n0 M& Z
$model->query('select * from user where id=%d and status=%s',$id,$status);9 d% a7 T2 G& s* C: i7 K
# f6 g; ~& S: |5 H3 s! h$ ]
或者
+ T8 O3 F- w. }! Y4 u4 t5 k$model->query('select * from user where id=%d and status=%s',array($id,$status));' q7 Q* b1 o0 V, |: E4 ^) Q
/ U1 u' ]8 N5 e$ ^' @2 e
原因:, q. ?2 {. T$ R$ y" a# c
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.+ d- l0 { J$ ^( r3 p( I( k
原函数:, w' {" c* P1 m/ W& D; H
protected function parseSql($sql,$parse) {
* q" ^; n O Q7 t2 n9 `+ T // 分析表达式- v: E' j3 r. Q2 V1 ~ @! E% `5 w
if(true === $parse) {; U% ` }( o; {% Q1 b
$options = $this->_parseOptions();
5 H" ?# {0 C: W6 s) l9 @) H $sql = $this->db->parseSql($sql,$options);2 @1 j' S" u. h
}elseif(is_array($parse)){ // SQL预处理7 `1 k, s1 ]+ A0 m% S1 T% E
$sql = vsprintf($sql,$parse);6 |! N( ~4 A7 ^% T* E
}else{
% Z0 y9 y+ ]5 d0 D $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));, V( k4 S! b$ P5 g8 j6 i3 X
}9 {5 P# q) E v5 u! Y" q
$this->db->setModel($this->name);: N1 {: Q9 q) [, G8 a, X. M
return $sql;
4 `+ n% L( `- ~' j9 t5 [! ]+ h' C }1 A0 b5 O& P, q7 Y. v* K! p
1 m# r" d3 Z! w |( i4 b8 q% _
验证漏洞(举例):
/ N, l$ p, E- s. D请求地址:
+ O4 u& O8 Y. Z& r3 E0 T+ Uhttp://localhost/Main?id=boo” or 1=”1
- i) W- F# C: L/ T1 N8 p7 n' T或
$ B0 F/ G. G+ g" e' T3 vhttp://localhost/Main?id=boo%22%20or%201=%221' H* s5 \" g8 m, w/ V, ^6 D7 w! G" h
action代码:% s6 _# b( t% @; z
$model=M('Peipeidui');
- f8 i" u. H% { $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);6 s3 ~! M5 A, f& D0 _
dump($m);exit;
. C9 }0 {( K* n k$ `或者
6 W; ]# a* M$ S9 u9 Q8 D t2 ^8 s$model=M('Peipeidui');
( r4 D: w5 y: U5 H3 j) u$ G+ G $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));8 A }& J) P4 T3 [7 B7 i
dump($m);exit;! k! y/ ?8 {# i9 T/ F8 _9 v
结果:
* G% Q$ C% }$ [) d表peipeidui所有数据被列出,SQL注入语句起效.
9 @. J: X$ k3 L1 w4 @0 S+ d- o( k解决办法:! {+ c0 X5 t7 r0 P
将parseSql函数修改为:# G5 T, H) s8 h8 S& P9 D" T
protected function parseSql($sql,$parse) {
- k5 k" S0 V% ]6 s // 分析表达式& o) D8 O1 [1 Y6 j* @0 ~( d
if(true === $parse) {, _" ]; p! K! c; G
$options = $this->_parseOptions(); e) U( D7 ~0 M8 x1 j7 t
$sql = $this->db->parseSql($sql,$options);4 z$ `" q; ?) G& ]9 `$ k- @
}elseif(is_array($parse)){ // SQL预处理
( e% P! n! P' c- I' m5 _6 g $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码' N0 W$ V% @+ x, K) @# w. S
$sql = vsprintf($sql,$parse);
# v( S& h' h- s% E* K* y. I }else{1 D! Q- B$ |" C
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
r1 R% e( M0 i }
7 a+ `" _/ _1 w& u# c3 q/ U) d0 t, I $this->db->setModel($this->name);7 ^$ L" m) k+ d% ~+ R$ d) t3 o6 L
return $sql;
+ [9 l& u1 v8 U# ]% g }% A2 K$ q4 O- q0 Q w6 \
/ R+ v2 b- H* R0 |
总结:+ e+ O, _$ D8 S* |; v
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查8 l4 @/ F* p0 ]* u) o5 [4 V
不建议直接用$_GET,$_POST
' O/ H* r3 M7 K& c4 x[/td][/tr]& k u0 T0 l6 t6 h; a
[/table]+1! g* Z/ w7 m# h2 F. z; m: J
0 f6 L" Y9 s4 A1 k/ {
; ~! P/ N/ {4 @
|