下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。' E0 v2 \9 [4 r
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件5 b4 @$ P4 o% `% t, H* S$ V: H
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
. I2 E- R4 |, Y8 v9 I, T" ^' R0 z) z使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
0 E! J3 f, O6 S! e% `$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();* p" ]" T1 w" k. | R5 d$ c, s) W3 ^
: y% e/ s" A8 Y& z3 H$ Q* i
或者2 g: j+ B0 q- A# E$ t: ~
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();4 \7 [1 _8 }$ i
* Z2 ~; j7 `$ @0 V
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):) @: \, a; J7 D( {) w# E
$model->query('select * from user where id=%d and status=%s',$id,$status);
6 _! J! ]7 Q/ w! {5 [$ _3 V; {2 A: A- L- d9 x3 B# h
或者
# q. u' B ~& d: c2 V$model->query('select * from user where id=%d and status=%s',array($id,$status));
+ k. B$ J' y) }) v: K* F2 Q% Y6 D
8 V/ F: M0 _' A$ K% g9 J! z1 Z 原因:9 l4 ]# }' D6 x+ X% S0 G
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
7 h& K/ A/ T+ {% ~原函数:
; w3 D4 F6 O' ?5 N# Tprotected function parseSql($sql,$parse) {. U# V. W+ O- g6 f' ~
// 分析表达式
6 D* R R& q0 ~" A6 d0 a" l if(true === $parse) {( c) P% |7 D! U9 g0 o
$options = $this->_parseOptions();
- E, t8 @, n3 G+ ]& l3 L $sql = $this->db->parseSql($sql,$options);5 I4 B# Y* \1 Y3 e5 S$ T
}elseif(is_array($parse)){ // SQL预处理
' R, `9 P% x- J+ l% L% c# B K $sql = vsprintf($sql,$parse);/ { y' r6 G4 a: X8 v
}else{
! I2 \6 T* Y+ O% s8 u $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
- m* s' Y! x' ^ }
H1 T+ r0 C4 _7 l7 L2 `1 m $this->db->setModel($this->name);
* c& u% e& p. z3 L2 n8 y0 P: {2 `- R return $sql;
0 ^; i, z3 w4 e; [ }( [' |1 B8 q" w$ t; ~8 ?
% D+ M0 R( o9 _6 [9 K* I验证漏洞(举例):
( e! _& O: W1 e/ I" b% J, @% v请求地址:
" z; l, N4 G; `3 ]http://localhost/Main?id=boo” or 1=”1) a4 z+ J) V3 v' N8 I7 S7 v5 J
或- W* P$ F+ W. q7 d: O) E
http://localhost/Main?id=boo%22%20or%201=%221
1 G. o. i% p, c3 O& ~action代码: [/ ~! W. M5 k Z* t
$model=M('Peipeidui');
2 ^" g& K/ g# [1 Y R $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);; {. @6 l; A, S* ?7 L1 l8 s# Q4 d
dump($m);exit;
, R. @5 {5 M1 e- v或者8 Q$ n4 G% G/ U3 P+ x
$model=M('Peipeidui');9 N8 z+ f5 n) a: m" G7 A3 [/ U8 t8 M
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
3 X1 A& u1 ~5 X& @7 D* z1 C dump($m);exit;
% I1 T9 W9 ^3 C3 P结果:4 K0 z# b9 F: E4 h" ?# G
表peipeidui所有数据被列出,SQL注入语句起效.
; K! X( D) R+ h! S# @/ m8 v( F0 a. Y解决办法:
0 P5 L1 r% f4 J& L0 Z6 ^$ M0 M将parseSql函数修改为:
; Y! D$ N5 _- ~ sprotected function parseSql($sql,$parse) {
3 q1 x% m2 G& U5 \6 ^( ]% _ // 分析表达式6 @1 ~% Z& r1 V. [3 e# Q
if(true === $parse) {
5 Y2 M4 k! ^# L/ e+ W) } $options = $this->_parseOptions();
: W0 {* K- _" S0 i1 G5 {5 K: @8 e7 q $sql = $this->db->parseSql($sql,$options);* z: j3 ^) T$ b2 V9 B, [6 i. a
}elseif(is_array($parse)){ // SQL预处理: w3 B" c3 v' j$ i% _
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码; M" f7 c* A% r( a9 T# [, _$ J
$sql = vsprintf($sql,$parse);6 y+ G+ T) i) o( n5 u) Z4 i
}else{. M1 b8 i4 B& K, n% h8 Y
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
3 }7 Q K4 U$ H5 k$ [ }
: f. N+ w4 B3 C) z! W3 k $this->db->setModel($this->name);
; ]1 B1 b& Z" y/ }7 v5 Z return $sql;& q- t6 y' {" y# Z+ C) F) F3 y3 r+ w
}
& W3 L5 C5 T) [" ~* ]4 Z* K/ [
4 S8 A0 W: I: K, m* O3 @" i总结:, K- K" h4 V/ s' E1 i+ Y/ a
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
( j2 j( v+ C" w7 V' b不建议直接用$_GET,$_POST7 S. c0 y6 e& T( y& @
[/td][/tr]1 t: ?6 z! p9 L1 P% h
[/table]+1
0 N3 o& F0 n. o9 |
. `2 ^* o" i: E& j8 M( Y( B. ~3 I3 k1 u: e, E
|