下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。8 G+ ? q/ u4 N, D& M- e* P
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
4 c, t2 Q0 H% s+ }5 q- E# h. y x根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
, X* u, e0 x5 k/ a: K7 i使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:. `! V; \" @; X! O9 [' q
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();; v3 G( B9 N! x# t
1 x3 Q( u, d5 Y8 q
或者
# \) i! j, i3 Y$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
$ |# V4 v; G; [7 A6 }. G1 a) B1 H$ n z8 I4 m5 y
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):8 }( J8 j$ ]; [8 e
$model->query('select * from user where id=%d and status=%s',$id,$status);
! G0 V8 y1 x$ b% ] h& `( k2 L r- s
或者1 G9 J' }" n: @+ W0 Y; |
$model->query('select * from user where id=%d and status=%s',array($id,$status));
/ J: ]% Q7 V1 x- [0 E3 X4 N$ A' k+ g% V
原因:
$ f5 K6 V5 M9 J9 h' gThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
; h% J1 x" K+ I* `/ k+ _原函数:) Z+ g& U' x" D$ s
protected function parseSql($sql,$parse) {
' \; b' k2 N. X' X* C2 x // 分析表达式
: c' C4 M; s/ C1 {3 B% f if(true === $parse) {0 q& ?" q; ~9 l6 n# f: D' q( `
$options = $this->_parseOptions();
8 ^ _" ^1 d1 {5 w' u$ H $sql = $this->db->parseSql($sql,$options);, {- Z( X" v/ Z& P
}elseif(is_array($parse)){ // SQL预处理( D8 ~& @' ]1 u, A; @( {1 i
$sql = vsprintf($sql,$parse);; j! ]8 _/ g3 t8 @6 p2 V/ a' s" c
}else{
. m# ^! ]8 c" B" ]& F* h( E) e: l $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
8 O2 |0 l2 `- m+ \2 S }
5 e5 S/ o7 q# D6 S/ x $this->db->setModel($this->name);
( F( i- x5 ~6 u9 x) v return $sql;8 Z' E) t( |0 F# Q" }3 l, v9 ]. q
}% h5 j4 _- I0 r; _2 J" ]+ G4 D
: f. r; u3 a( e0 e) r; _1 S) s
验证漏洞(举例):
+ f; O4 G, z `1 i! ?请求地址:, G) q9 O1 j+ J+ k9 P
http://localhost/Main?id=boo” or 1=”1! k6 C c% ~6 E q
或
! g ~: | ~: y& zhttp://localhost/Main?id=boo%22%20or%201=%221" |# F+ e5 D, _# `8 n# C8 h
action代码:
$ r) Y8 o& H7 m# ]6 Y& [$model=M('Peipeidui');
6 }, f; R# o( ~6 B0 y0 R- { $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
# O. M& [5 _6 o( f+ m5 K; k dump($m);exit;# j2 Q3 l: R" }6 G/ k2 Z( c1 s
或者
* A4 `3 s' k0 ^$model=M('Peipeidui');
7 L& U9 r5 `9 m: T $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));/ ^2 o& u; b0 w1 F @" K' {
dump($m);exit;
2 G3 ?5 o8 m+ Z5 o* q结果:
5 M% ^& L; W' v, A) e, y" q表peipeidui所有数据被列出,SQL注入语句起效.
' w+ I) w) F; t: S% }解决办法:
7 {0 F. T& G9 H0 f3 l将parseSql函数修改为:' M1 I7 g1 M; x V; G
protected function parseSql($sql,$parse) {1 z3 F; x2 z; S0 o
// 分析表达式
+ T6 ]/ Q4 w5 M/ N# e if(true === $parse) {- y' D1 r' `$ E/ m
$options = $this->_parseOptions();' c8 d3 S9 i) v3 v" C, J
$sql = $this->db->parseSql($sql,$options);0 ]( T* ~; C/ I3 w5 J
}elseif(is_array($parse)){ // SQL预处理
1 K8 ]5 ~8 i9 L1 ] $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码! _4 C/ i' e7 g7 z @
$sql = vsprintf($sql,$parse);
& r6 B G8 F: B- N- E# x }else{
8 r+ [4 U- \# @+ m8 `9 a $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
* b# A% [: ]* Q2 Z, G2 X" p: Z }
4 l: D, H7 i3 Y6 _+ |. I2 j) f. y $this->db->setModel($this->name);
' Z0 V% A4 q- U9 J- I1 T return $sql;
! i/ j: F5 x- |3 Z$ i }
: | ^7 | `* V- Y1 p
! [% \9 Z& w% k% U总结:
% H: {+ s" `* j( v4 d不要过分依赖TP的底层SQL过滤,程序员要做好安全检查% D' b( R3 L4 p+ e2 }2 v; `
不建议直接用$_GET,$_POST
4 h2 ~6 P6 e$ ?[/td][/tr]
% P, X6 ~' `% D! o[/table]+1
) y& {2 A, X3 g/ s: {8 |3 J/ P' p) Y' P1 f+ T& Q7 i. m5 e0 y* [5 B7 G
# E- b+ I, z% I( S6 k |