下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
" o. s/ X& u d8 O% r$ ~+ L. PThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
) o3 |8 s& o+ }! o O7 l根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)$ R9 z9 B6 `; i( H& l" ]7 N
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
1 ?8 i$ m: Y2 l2 E$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();1 X7 p# s; t9 N
# a9 G, g Q' p" i8 G- V3 ? 或者8 `/ ]; v1 x- l' }3 j: G5 {# g- p
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();% W& H/ [# k- x$ s- o- \
6 _4 r4 r, B: K
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):' z8 K4 U- ?* f6 \5 v1 R( Q
$model->query('select * from user where id=%d and status=%s',$id,$status);
' }' n x9 _" H3 {6 l& h9 @: u- M9 Z. h3 y! E
或者' c2 G Q- T& s$ z" |7 x/ ^7 r
$model->query('select * from user where id=%d and status=%s',array($id,$status));' n! C _2 U9 g4 t% m/ i# p4 h
' c4 F9 t; B" s/ ]
原因:' l# L' o0 ^. o" K) m. P
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
1 l) `4 H. n5 m原函数:8 D' A9 a0 q+ o. H
protected function parseSql($sql,$parse) {
d) F. P5 s: f% A$ e // 分析表达式
3 V& V5 J! ^- h* M+ c if(true === $parse) {
5 ~/ R' P6 _; j7 m1 I- a* I $options = $this->_parseOptions();
' G/ x, n3 w# \/ K: ]8 K1 Z $sql = $this->db->parseSql($sql,$options);9 b& j! v0 y: k( ^
}elseif(is_array($parse)){ // SQL预处理* h( C2 u/ d9 ^
$sql = vsprintf($sql,$parse);
& u* t6 d X" G) _% D/ G }else{' Y2 H3 `0 c/ }% d
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));+ M/ C3 a. q: _3 m- A& j H
}0 \* O9 r% c B% k# a" S9 X
$this->db->setModel($this->name);7 q0 A) {' M, c
return $sql;
- I \. R: t6 C4 D" e1 l" [ }
9 y* Q7 g: L9 n2 A! z' R
K: t1 g# O& s& g( n# J* \验证漏洞(举例):5 R7 }* K6 O- N
请求地址:: ~% ~3 S1 T% k3 l/ W+ a0 ?
http://localhost/Main?id=boo” or 1=”1. j% Q& F- o+ z% u( e9 l, _
或9 `) l0 b( o2 ?. p7 f3 g" J, z. d
http://localhost/Main?id=boo%22%20or%201=%221
( x2 f! c+ ?6 _+ x7 v6 d8 gaction代码:
5 d5 e5 x8 P* ]% r$model=M('Peipeidui');
8 T1 @5 `; Z6 i9 ?0 @. q $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);/ G7 O- O. @* j1 K5 I
dump($m);exit;; Z4 C0 w7 F( N% f+ j9 e
或者- t% {3 N0 A- U4 K+ |
$model=M('Peipeidui');
( N1 _0 B. p6 G' @' \0 H $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));& E) s! P' G% p% o
dump($m);exit;
7 ^' K! J- G# F* V/ Q2 x. x4 ^结果:
; s, k/ R* ?+ A0 P `表peipeidui所有数据被列出,SQL注入语句起效.
% E& s& o3 U& }9 U% }0 v V解决办法:. b' _. J O5 z
将parseSql函数修改为:
$ e( @2 ?1 {7 R2 l: e! |6 jprotected function parseSql($sql,$parse) {5 ?$ `* s$ l! S3 e7 d3 w1 i
// 分析表达式8 l- S6 @! o& v+ D
if(true === $parse) {( [1 [% M" t, Z# }4 x# [8 Q
$options = $this->_parseOptions();
$ X6 b- S/ C* C5 ` $sql = $this->db->parseSql($sql,$options);
~/ a) B& n& R0 s$ [ }elseif(is_array($parse)){ // SQL预处理% i$ E( y0 _8 I v
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码0 i! I& @: D+ b# q6 d+ o0 o! R
$sql = vsprintf($sql,$parse);3 q$ s" F% n% z+ I
}else{6 l8 H+ {+ i6 L; R) c
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));6 f; R, v8 `2 F. H# W1 D8 g
}
) n- ?% {# W& \' Q" ~ | $this->db->setModel($this->name);% ^ U5 w* g7 q Y6 F
return $sql;
2 B( t+ L- r, J0 M1 K8 i; P% p }
$ R# {& B# X: S! J$ x# K/ W! w, ?3 k8 t# a9 b9 D
总结:6 O0 C/ ?/ X* o* y
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查( t8 x0 ^9 Z) N( ]( s* y
不建议直接用$_GET,$_POST
R: ~9 {! D$ F3 X7 b2 K[/td][/tr]( \0 Y! H0 W' {2 N* {
[/table]+10 _- N: W2 X1 P5 v. z7 C- H0 Z; U+ _; R
1 y% c: p0 B' H) j) Y
8 G1 k; f# C: Q. E8 `! b0 b* @/ D
|