下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
! y) I6 t& p- [7 y, vThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件+ t2 R, n( x# P5 v/ O6 `
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
4 Z1 e R' j2 E0 W5 s. ?# a使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:) o9 o! R; ^8 V# v3 ?
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();5 l/ q- i1 }$ v) _* H9 e
4 t* B9 I& X2 W& Y+ |" O. q; t
或者4 [ p U) S# ^6 H! b L
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();6 q/ s* ]6 c% D3 ]9 _& @6 H
! ?" k; h4 v0 w, k3 W3 T0 o 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
2 R4 ^! b4 J) `$model->query('select * from user where id=%d and status=%s',$id,$status);
2 F3 w/ ?2 Z o) y' f, U
# {/ t/ j h5 z- m7 M1 c或者
2 G$ Z3 a& u$ R( B( F$model->query('select * from user where id=%d and status=%s',array($id,$status));" m0 i4 Y% _! |* @! e- `
" X& K7 v( }: Y' O
原因:
6 R% ~( f# a' X% w& Q# \ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.7 N1 K" Z4 i8 |
原函数:& ]; d/ ]1 B) u, K- Q$ b _
protected function parseSql($sql,$parse) {
. e, Q+ M2 a8 C: ~9 F // 分析表达式
9 x8 X5 q# q8 i) o- X if(true === $parse) {
3 F' l/ O& P2 i9 v, ` $options = $this->_parseOptions();
8 C4 @3 c" n) a $sql = $this->db->parseSql($sql,$options);
8 {, A! |4 _) {/ p; k: U* `/ {& J }elseif(is_array($parse)){ // SQL预处理
5 \7 ~3 D6 q! Q* D: O $sql = vsprintf($sql,$parse);" }5 t+ I8 @. x: |$ r/ L
}else{
) t, v, z- e9 J4 M! {4 t- P $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
" r. f% u- v5 B4 g7 k; q! j }
: `; k2 E6 n! o% o$ J $this->db->setModel($this->name);3 r* |5 ]3 x. D3 M6 D" c
return $sql;) \" D# O+ ?% {& s" x; u
}
" S. X' ?: o# P B# G' V) s, g( p; s( ]% Z/ b) V
验证漏洞(举例):
& S( u3 S- [, y5 h6 f* P请求地址:! }8 @7 e6 E: C! j1 o
http://localhost/Main?id=boo” or 1=”1" `& I! T0 i! y+ l- S1 f
或 m8 o g3 s0 ^' D& b8 ]! u
http://localhost/Main?id=boo%22%20or%201=%2219 |1 q5 s F" z9 A
action代码:
& G+ C) y! }( E+ d& b) A$model=M('Peipeidui');) L/ ]0 |6 U2 t. S& `4 O8 a
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);$ x4 |( Q- K3 n$ J
dump($m);exit;
| W* l# e0 ?或者
: `/ r7 @+ o3 F/ z: K- K: F! t, O$model=M('Peipeidui');" @- o6 z' U2 `/ B
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
' g* v# U* o7 n6 b( o4 K' r dump($m);exit;# E V3 a" o: Z, k0 A8 o. C( q: |
结果:
* C; F' M8 H0 W( C$ E表peipeidui所有数据被列出,SQL注入语句起效.
V. Z) J* L5 {0 \+ R解决办法:3 C8 N3 ?# ]+ x% }/ L# v+ H* o
将parseSql函数修改为:1 V4 H/ K7 y0 B8 R, B+ G
protected function parseSql($sql,$parse) {
% I, K/ C8 y: c7 q2 K) Z // 分析表达式8 ^/ @+ u- d" w0 B: ?- m2 `
if(true === $parse) {- _& s' b L; |% l5 G' }% O
$options = $this->_parseOptions();
8 _9 D* C, u" n. b& P8 F' L/ }# b $sql = $this->db->parseSql($sql,$options);
4 S7 M+ F* e; B+ m }elseif(is_array($parse)){ // SQL预处理2 L! q0 n% z- A: J3 j+ {
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
9 q- \4 h8 e y6 C) c( A $sql = vsprintf($sql,$parse);' \7 a- `' O% }# g. S: l
}else{) N5 x! B7 l5 z2 x0 q
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));4 L3 A2 c* H1 S: D9 T+ @+ r
}
: {# b: ^& U; u5 V6 _, h, C $this->db->setModel($this->name);4 s- P5 _6 i+ q: T! L( Q
return $sql;7 F2 `$ x8 r4 @/ G
}5 g- t; t" b; g; Q! @7 W
1 v+ U: U8 S# j! E3 x8 y. g1 w总结:/ n# V; W& j' z+ T! S7 X
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
3 A! J5 F9 Z8 L5 x7 u不建议直接用$_GET,$_POST' k3 m/ ?4 a5 q/ l
[/td][/tr]; e- W4 ]$ l( m+ q% }
[/table]+1& C% }0 }. h6 O* _$ ?3 Q
/ z' W- N1 l$ V: `% l- r8 q
1 k& M5 D+ M/ O+ g# T |