下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。8 K$ G' q+ }( S. X- H
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件- \, b e& X0 k7 ^
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)) T% e$ j; L8 q$ B* ~" V; F
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
" g( K# }. m# N# x! F0 R& \$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();4 s' _% G$ L5 t9 l
) k m) G8 F3 x- D: x B 或者
0 c4 {) F$ ~0 X: E1 C$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();/ {. K4 t6 ?$ c6 b
# j3 ?8 r D4 c, n 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):5 |: m$ v% Y. U
$model->query('select * from user where id=%d and status=%s',$id,$status);$ I- p& _* T3 d4 K, z1 A" e
; |' D- _4 p$ f1 i6 j3 m或者2 q& Q: Z' |' N( V q
$model->query('select * from user where id=%d and status=%s',array($id,$status));4 [7 B6 F: w5 }. h2 c$ ?/ j
6 W4 H7 d, N% x5 p- s 原因:+ A4 \3 X* O; H3 L' j$ F
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
" K% S4 F$ f; @0 G4 {' `8 ]5 }原函数:
7 h. q ^) y5 f; fprotected function parseSql($sql,$parse) {0 }& u* P8 L$ ?, t: Q. u5 O! S
// 分析表达式- N" A/ S. r5 H {& k; @9 K* i/ S, O
if(true === $parse) {
2 c( n: g s9 b7 k $options = $this->_parseOptions();: R0 @/ O; b/ h: N7 X
$sql = $this->db->parseSql($sql,$options);
( u! m, {. H/ ]4 v; y7 F }elseif(is_array($parse)){ // SQL预处理+ A3 K; o$ ~ }! ? I: }
$sql = vsprintf($sql,$parse);+ M" x! I* n N
}else{0 V3 q: v0 s2 x, b3 U
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));$ h4 `" Z# o0 Q( J
}
* @: Q( D. @# y9 |( z, X( A: S( D $this->db->setModel($this->name);* v) h& c3 R1 G
return $sql;/ P: g8 K- l# l: u2 B0 D% P' \* c
}
+ M, z+ C: k8 \. C2 o- \7 U1 U6 O
: d2 K- r/ d3 K4 V% T验证漏洞(举例):
2 P7 c! A2 |1 `7 G6 `7 j' v请求地址:
% \, ?. Q2 ^1 r9 x ^9 L5 ohttp://localhost/Main?id=boo” or 1=”11 E+ Q# D+ Z. p5 p5 P9 }
或
z6 Q, ?' x& G1 G& X9 [- B% ^7 _http://localhost/Main?id=boo%22%20or%201=%221& W! s$ L/ T5 H
action代码:- [+ H* v, L1 W, f3 v
$model=M('Peipeidui');3 k5 a7 ~2 p9 F) |
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);# F! Q+ `0 {/ T5 `& E: P
dump($m);exit;7 N" E$ v7 l9 n. _7 _5 N( i6 k+ Z/ \
或者
! x$ V9 J2 ?$ m& `5 L" l+ i. S& O$model=M('Peipeidui');9 _8 W4 S+ D0 @' E
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
$ W2 b+ F5 T' n! @" a! o- M dump($m);exit;
* z2 p/ h) O; J( [/ C8 W6 ~ J结果:% H2 ~) G& u& }6 {* }$ |$ p* W
表peipeidui所有数据被列出,SQL注入语句起效. G2 [$ F4 }7 R' D1 I+ V( l
解决办法:; d% M. z1 t# q
将parseSql函数修改为:
5 K6 I4 g" N3 y$ ~# U) rprotected function parseSql($sql,$parse) {. n! [! q4 A4 B2 H* h8 H0 n/ j
// 分析表达式
. _0 L4 T; X- K) @0 l$ C* ` if(true === $parse) {
- [, V* I( R8 ^ $options = $this->_parseOptions();4 h- _! O. N d5 O' e" ^# C
$sql = $this->db->parseSql($sql,$options);
: t. ~+ j# A+ }) k h/ n l# P- a }elseif(is_array($parse)){ // SQL预处理
- Q; }# i4 j) L+ F6 R9 q& z) M9 {; t! j $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码 E2 z0 u" R% u( C/ @$ B& [9 i
$sql = vsprintf($sql,$parse);
0 e. I0 v3 a J' L$ f: o }else{
0 E' g. Q2 M& f9 D* J, S3 |+ d $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));6 Q r, P) C, P( M! d
}
; i$ g/ B O @2 ? $this->db->setModel($this->name);
/ A4 V( H! h R3 Q% ?' R$ v return $sql;* l# R' X% O% ]) |2 J0 o
}
# c8 U) z9 n$ ^5 i1 j- F" [
+ ?& T* `2 a4 d8 T- v3 ]总结:
2 ?5 D4 o5 _1 Y6 C不要过分依赖TP的底层SQL过滤,程序员要做好安全检查% d! J3 ]' N* O4 Q
不建议直接用$_GET,$_POST; }+ X# e7 Z! t# |( z) q' h# J; _ i
[/td][/tr]$ t+ g) W1 M+ k3 |: k5 `6 B
[/table]+1
0 N6 S1 i' |$ g$ k( O; A! Z0 q7 r3 n; E
2 B7 I& m, h+ v. K6 n! T
|