下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
+ c/ v+ O7 F! r, f- Q) w0 F: H/ x3 QThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
& E6 S/ O' [5 ^; ^9 E1 v6 o, @根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
# Q3 u! [4 S( G1 g0 [" `使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:1 F c& M$ T, z& d: M& k9 F
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();+ f/ `6 H5 X. [: z" G( x' `
6 V; l( i( C# j& K 或者
: L* h( _. T7 x$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
9 f: o, D) C A% S( w8 e0 H2 p
4 Z+ _ ^* w: P- x" E7 ` c 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):/ c* q) r M% e* |
$model->query('select * from user where id=%d and status=%s',$id,$status);( q3 S) E) X h4 H8 e
8 \" b/ N4 |+ h% ^0 O1 o9 p或者
* M( w f% q+ z8 e- \ Y9 d8 G7 }$model->query('select * from user where id=%d and status=%s',array($id,$status));
@' [4 w) S: L
2 {6 n' f/ Y$ t, j4 x" h 原因:
8 J" c* m7 A; [( j/ H" |1 FThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
3 T. X& E6 a0 d4 |原函数:
5 U% g( T7 |" ^5 A4 m# \9 Qprotected function parseSql($sql,$parse) {+ C' w! o9 k `5 _% }
// 分析表达式
L# E1 F# E' t3 o; h if(true === $parse) {
3 h# ? L2 z+ B: R0 [8 g( Q $options = $this->_parseOptions();; `$ v! J% @) z4 w$ a( m; }
$sql = $this->db->parseSql($sql,$options);" P8 _, R9 W8 w8 b4 c- {
}elseif(is_array($parse)){ // SQL预处理9 d7 r0 V2 x, }! R8 ^# x1 Z
$sql = vsprintf($sql,$parse);
5 ?& ], S0 j& ~7 M( U }else{
j% ]5 D. A. }# M, r$ b' h! m $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
8 }' h- N5 D: W }
2 \% _9 U* H, N/ v- ^ M& B" ] $this->db->setModel($this->name);8 k( G1 G2 W" r* z
return $sql;
9 O& Y3 |& X$ |3 T( r }
4 p7 ~5 E ^6 W$ `5 J
* [+ p0 i0 Y4 n! o, D4 M8 w: L验证漏洞(举例):' O4 o* r5 c/ n1 D# Y
请求地址:5 M/ O+ J; ~5 t
http://localhost/Main?id=boo” or 1=”1
5 K4 Z7 m3 ?6 Q( p5 G. v/ a或. Z: R0 V. q6 l- F$ Q' Y; j
http://localhost/Main?id=boo%22%20or%201=%221% I/ `4 ?" n$ G
action代码:; @/ B5 k; E: W" {9 V7 B
$model=M('Peipeidui');
: t1 [2 K! W: k0 |2 Z3 F8 ^* W+ g3 c $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);+ V1 Z/ r8 s* B l9 v. r" Y7 o" k
dump($m);exit;
5 o8 _9 m( e- }或者: |5 ]) `! x$ r- h1 [0 M6 B
$model=M('Peipeidui');
/ Z* e* K' L* ~! j' q $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));6 R0 n) r/ l9 q
dump($m);exit;
* |' K7 W5 ]: U& A结果:
1 Z5 y' }) N# k @4 x* Z表peipeidui所有数据被列出,SQL注入语句起效.
' }8 M K5 R I+ p$ o+ H4 O% N解决办法:
( Q$ y2 u/ W* l: z8 A将parseSql函数修改为:/ a/ t3 I7 g/ l4 e9 L5 O
protected function parseSql($sql,$parse) {
]2 [4 C, I% @# a, ~( s4 Z( n // 分析表达式
3 @7 m4 w: E. Q% L if(true === $parse) {
! u! O2 |& k' M, D* Z $options = $this->_parseOptions();9 x% `8 ` A6 T% s% k: M/ m( |
$sql = $this->db->parseSql($sql,$options);* [- R$ e; Z) R
}elseif(is_array($parse)){ // SQL预处理
! Z, o4 R1 W; W, g) x: T $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
; q+ R; q# c4 F $sql = vsprintf($sql,$parse);/ m) y4 d+ R0 h- D6 D& K
}else{ x, `" z9 Y: _/ X& }. B
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));7 D% J+ Z! I w& u6 ^- a, v8 [- L
}
( V' O4 K% T4 w6 |" G. M: D $this->db->setModel($this->name);; y8 M4 N; Q9 L9 N) |: b6 M
return $sql;
- d; ]1 c/ C* k% b d6 z" a }
4 f1 R# l$ P+ E; J
$ j; T2 Q8 X/ H& Q% `/ g总结:
7 L& G7 ~6 x$ \ j2 p, N Y$ h不要过分依赖TP的底层SQL过滤,程序员要做好安全检查8 v' j. n+ r. \0 A: [ |( U
不建议直接用$_GET,$_POST- M( Y( r+ X$ x# I
[/td][/tr]
: `% G* ?1 G( e[/table]+1
, m1 t) o: ~( i1 \; `; o
& ^9 f; S8 s2 w$ A1 [
# K8 S1 o% Q) g6 | |