下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。% E5 ^' A7 m4 \5 P
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
3 v+ d% O/ Q& @6 I8 z0 X根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
' ~' a2 ], T" n- G; r I使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
) V2 F( O% s3 Q$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
! ^- Z. ^9 M" b% ^. q
3 [1 G$ z. `% N$ O: R' x 或者- L& }) ]2 d, {2 h% j7 f
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();' R" p7 P8 e4 y
. F& s/ I( ~7 Z5 g' K0 x) J0 n9 Q
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
4 `* C) `) l1 r) m! g+ b6 s' L* s$model->query('select * from user where id=%d and status=%s',$id,$status);
* a/ ^; I3 |/ `- J) W6 c- z& Z5 n
+ c! I8 N9 g2 W) m0 g3 S1 ?或者
2 a) d# N7 L# B6 F9 |$model->query('select * from user where id=%d and status=%s',array($id,$status));
8 J& L/ J9 g% V3 r1 A1 n$ S) v( s: n) e' g& u
原因:
! r+ [" g2 m' n. ~3 g0 {: wThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
# J4 V8 Z& W- s x原函数:
" _7 U4 \3 H, _6 [4 P }protected function parseSql($sql,$parse) {
9 G/ A. B9 P2 q4 [9 L // 分析表达式# d7 j6 c- q5 l; |% s
if(true === $parse) {
5 m- M- I: J2 I$ C R$ k! A6 y; v $options = $this->_parseOptions();, k6 B. J( w, e" v) a' ], k7 T% T
$sql = $this->db->parseSql($sql,$options);, o5 ?# D. S6 _& n& B1 ?. z
}elseif(is_array($parse)){ // SQL预处理
* t2 V; o* ?/ p" p5 x" u; U $sql = vsprintf($sql,$parse);
9 B# M" ~# t+ Y8 m: R! U( n }else{& O. k$ t. h3 c( d* e1 R
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
% z: t- C- n2 H }0 A; }! X7 J$ ?" n+ p$ @! d: X
$this->db->setModel($this->name);
9 R: J- F6 v6 f: \0 r return $sql;& S; t) k5 |3 U1 i: r/ W' ^
} F2 o, ~& W5 Z4 k4 T
4 l; V7 t9 R3 K# ~7 \: K
验证漏洞(举例):. j5 K0 h+ c: l6 x- a9 v4 h
请求地址:- e# W# M. t; g6 @) ]- ~2 K
http://localhost/Main?id=boo” or 1=”1
8 d, j3 a4 x: b/ V0 [; J或
! s% ?7 y% F+ h$ e8 e, Z) `http://localhost/Main?id=boo%22%20or%201=%2213 G5 O/ R8 e- z; f6 H- D
action代码: |/ ^' I( h |8 j. R
$model=M('Peipeidui');1 k8 p/ L! W9 k$ C% l+ M
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
6 H& u$ n; a; B dump($m);exit;
5 ]4 L A$ V6 h! N8 F+ j或者
3 X1 G; { g* m- k+ E* i$ G+ s9 `$model=M('Peipeidui');2 t" r. U0 f# R
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
Y( j) W' [0 v0 |8 Y$ G( e dump($m);exit;
) X! g: K8 k& J. w0 J8 ? s结果:& Y! m7 ?5 E8 Y" [* o% N
表peipeidui所有数据被列出,SQL注入语句起效.
9 B; f* y4 e% p2 J5 ^+ _& F解决办法:" p# w9 z3 U( b" B
将parseSql函数修改为:
' O- X6 Y- ?+ ?protected function parseSql($sql,$parse) {
, D1 e# \+ |9 v1 L* x# A // 分析表达式
& f3 D% w1 Z \ if(true === $parse) {
I7 `* O) o# T: r" `& X $options = $this->_parseOptions(); _" I9 k" t" ?7 {
$sql = $this->db->parseSql($sql,$options);
6 H, v' b. c, d9 n0 K5 H }elseif(is_array($parse)){ // SQL预处理' F3 X. s$ U0 [8 H; @( Q3 Y
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
V, q; S. u8 H& z8 X, s $sql = vsprintf($sql,$parse);
- ]! o s2 Z3 }* H }else{2 s+ }9 M2 [3 x' U! k* o
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
. n7 t1 v5 K% ^) J1 G5 E }. A0 L3 g6 u% e2 G
$this->db->setModel($this->name);
8 W4 T+ _- y# p, U) R" } return $sql;
+ n! F3 i8 _* b2 d, b9 E }
* s0 c2 l; f* w6 t" F; c5 F6 ?; k# T& C' W* r$ S1 @9 E4 }
总结:
5 k9 x) e& w F; K4 Y) T3 r; B不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
$ z* e' m1 U% Z5 Y- C不建议直接用$_GET,$_POST- R1 [% k/ K* g+ V9 |3 `& Y3 u7 T
[/td][/tr]
+ R2 C# K1 w( u) O x# J[/table]+1
6 r0 m, h' \1 l7 H+ g' \5 L5 r5 _8 o2 a+ N- a4 D
/ s. k! d. T/ {! O8 B0 B8 I0 Z |