下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
/ L7 V: M7 O2 o* q1 B/ x. m9 VThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
7 g- I _7 _# j5 s: X: t) Y根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
* w$ g6 l) h2 B7 `7 S/ K使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:9 ?1 _7 m3 B+ V A- S
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
9 q* S8 F* S- J; M
: P, B: E- I7 m. P& D- X T 或者
) x7 H( G0 f6 q0 M1 C$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();$ @ q; W( S; ]7 p) L) t
1 M( y( ]- d0 q' c( a/ b
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
) s% ?4 V! Q8 q2 u) l7 g9 v$model->query('select * from user where id=%d and status=%s',$id,$status);' T/ ?: e' t4 t0 G8 `
0 Q, y& ~' F; b/ ?) J, t3 f
或者
7 d: n! ?- z1 q- T2 O6 ?$model->query('select * from user where id=%d and status=%s',array($id,$status));; j+ |% `+ g2 m( d4 q1 z
+ z8 [3 s$ m# R+ v) R 原因:. x& n b6 f. P# w
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
/ j7 n% L! e, b) l原函数:! s4 @+ _- u( p6 i+ ]5 T
protected function parseSql($sql,$parse) {
M# O/ [" i9 A5 V7 {3 l, H- ` // 分析表达式 K! w& I9 _* k' v1 c$ A$ R
if(true === $parse) {
# v5 P7 D3 l9 \ $options = $this->_parseOptions();
; t$ E8 \3 {" X" |, G; r) F+ s $sql = $this->db->parseSql($sql,$options);- b& C! A. ]' J( j& y0 _( x& u
}elseif(is_array($parse)){ // SQL预处理( T$ r. m4 _# g7 u+ V
$sql = vsprintf($sql,$parse);& M! R3 c9 t8 f/ T' p( n( m) a6 i
}else{
7 ?: ]; c7 A" b% ?/ w $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));# b4 m9 v6 H' s& A6 W( z# M. V' [& H
}
( w& \) X3 f# {7 \4 r $this->db->setModel($this->name);" c0 @" z2 B* h0 l8 k
return $sql;+ C% p2 ?& r) Q, O
}1 S5 G6 j0 Y: u9 r$ G+ l- {' h
' p8 V$ i/ R) s) C" v' q验证漏洞(举例):- d( Z6 a" C) g' y6 K( n9 Y
请求地址:
8 L" `, }( y( b$ J, A% khttp://localhost/Main?id=boo” or 1=”1; k: I5 e- P# e3 v7 ~ G
或( A9 d* i7 l' c- |# ~
http://localhost/Main?id=boo%22%20or%201=%221
9 n( l. V/ n" R9 Jaction代码:
. l" ~- b: X$ a* U& x$model=M('Peipeidui');
1 g* [/ u3 y; Z1 q0 B, L $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);/ f$ s: m. N, y9 Q
dump($m);exit;- L3 F; M) O) {& z' z, j
或者& s% I, C$ p0 g$ k* R
$model=M('Peipeidui');' H6 B7 S3 `0 I& W' @
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
0 i k, E) m( @4 x dump($m);exit;
% a/ |/ `' O7 n! p6 {6 h" p: G结果:
& j/ ~9 i- c9 I1 |/ m2 y+ n表peipeidui所有数据被列出,SQL注入语句起效.
. g" d8 f* Q) X+ I; v解决办法:
* [$ [) F! d5 R, C/ q将parseSql函数修改为:' p1 C) d4 m' w- f
protected function parseSql($sql,$parse) {
, p8 w/ F* n D: s; l. x // 分析表达式
, B! E6 W3 V$ A2 H9 T; a1 f$ B if(true === $parse) {6 N# d3 U4 t' A- P6 U
$options = $this->_parseOptions();0 O8 f; l" f" Q, k! L
$sql = $this->db->parseSql($sql,$options);3 o5 ~% r1 r) o% v0 y6 n U
}elseif(is_array($parse)){ // SQL预处理& o- d6 }& P j3 v! C! F% r
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码& d: ~8 R: u! }: o3 z+ |. o
$sql = vsprintf($sql,$parse);$ z" D ]$ y3 c. ?" i; c
}else{6 J* x, t+ G! b3 @5 \! z% C+ d
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
* G3 G& Y% Z& x$ A$ y' U' X. { }( \0 O6 o" Y3 K/ H ~- s( H1 Q
$this->db->setModel($this->name);
! S0 F. Z. H9 x0 ~& {5 J return $sql;
H$ A7 D1 w: L9 n+ \9 C h }4 \2 i* E1 z) g# t( C
8 v* j/ r5 q; q( ]7 U9 B O
总结:
4 ]1 W. m, j0 O Q) u不要过分依赖TP的底层SQL过滤,程序员要做好安全检查8 C% }0 C, }# {# o4 P, ?7 ]
不建议直接用$_GET,$_POST# H+ H1 M: r j# T/ F) o
[/td][/tr]8 ]& D" R7 s2 m' a* F7 m, s
[/table]+1& B, L7 V) H1 C
. B+ a0 Y) q1 [5 B5 `' B8 ~6 F1 q" N# J3 ?& `
|