下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
/ I6 a2 _ f$ ^$ N5 R6 o m) FThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件& j" y( W2 w1 G9 R( A E- U
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)7 P, P1 g" E, T# Q) q# C7 L
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:( g1 D. E6 Q; u( F" h+ A" r5 e. A
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();! v# x3 d9 `. E3 D
2 A. W% O7 y3 `$ `! @: H/ B4 ^( o
或者, J! y: s t0 Y1 i( F8 \: \
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
4 t, c3 o* p+ c4 H' ~4 O
( }8 l' D+ d# y$ I5 T5 h/ C' C* [ 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
# Z9 J' d1 S; X2 t$model->query('select * from user where id=%d and status=%s',$id,$status);
2 {0 ?( _# m1 I i4 [
$ E& D0 @6 _( Z或者! L5 q1 c3 N& k
$model->query('select * from user where id=%d and status=%s',array($id,$status));2 O1 C/ g) l$ V6 L' |( W% o
" u5 b3 z1 g8 ^& F
原因:2 h$ A( G, D# e6 V3 Q+ Z/ n9 f+ x
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.2 m" [3 o5 ^7 p3 c# v
原函数:
& X }: [; n& m& h# L; Z5 Jprotected function parseSql($sql,$parse) {2 u# a# q# q) T( s3 P5 t( F8 j0 V: \
// 分析表达式9 a7 L# q, |9 }# X* ]
if(true === $parse) {
5 E0 I+ b k$ f4 t; h9 G4 b4 A $options = $this->_parseOptions();
9 d. Q7 N3 @ ]: h& L, g& Q $sql = $this->db->parseSql($sql,$options);# Y0 ^" j. `* O/ g
}elseif(is_array($parse)){ // SQL预处理, B; i h) C* d. S' U* d K
$sql = vsprintf($sql,$parse);# o$ @0 O0 h5 J7 ]; b+ L9 f, L
}else{
8 `3 ^9 [4 s E2 v1 q7 |' X $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
! e9 r8 e& r4 }+ M3 A" D }
; O- h3 K) z5 n2 L5 d4 i6 j $this->db->setModel($this->name);
" j G/ w% G% Y0 Z: q- f return $sql;/ ?8 c t; ]: S% n& y5 h
}5 @8 Q5 n& S9 n# |/ J3 C8 ?" {2 w
; K: L# U( Y& V. M验证漏洞(举例):. d4 O* o% ?% u) F
请求地址:. w7 e6 e1 Q- }) M! Z
http://localhost/Main?id=boo” or 1=”1( h! j0 [" `0 d
或
9 m) C H4 R0 \; Phttp://localhost/Main?id=boo%22%20or%201=%221& U1 a. `) r) H/ E) b. p- a
action代码:7 N# Q2 D( e4 F
$model=M('Peipeidui');6 K i& r1 h4 Z$ }$ c4 q
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);- a: H; @8 f- C) g/ i- b
dump($m);exit;4 C/ M' W) D) K
或者
9 U, z) O6 J$ Y6 `, |$model=M('Peipeidui');- E, r5 I* D3 `; g0 Z* z
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
: V5 t1 t5 B/ ~: m; P8 T" d dump($m);exit;
% {5 Y; P7 k2 c# m, {( Q% Z( Q8 o结果:0 G; a# \$ `- u7 Q/ ?2 V
表peipeidui所有数据被列出,SQL注入语句起效.
: C( X! a7 B5 X7 \解决办法:
+ v6 ]3 N2 B- f, r( p将parseSql函数修改为:! z3 ~7 D1 G5 X! w9 K- l
protected function parseSql($sql,$parse) {4 s; t: @4 Z2 k; t1 J
// 分析表达式$ W6 K& S6 ^" o6 z8 @8 j& ?
if(true === $parse) {
) o0 ^+ i5 C6 S( E2 G $options = $this->_parseOptions();) u& u' x" @; e/ i
$sql = $this->db->parseSql($sql,$options);
+ X( P* C z* ]4 i- i+ U }elseif(is_array($parse)){ // SQL预处理
8 L+ F* |# G6 ]! T; Q" F $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
/ S. f& I' h. C' R $sql = vsprintf($sql,$parse);: L. n8 a m/ Y3 N" S
}else{) f; _1 W- _! p2 M3 {8 E
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
1 X9 P, A; c5 u$ j }
: e5 ^. F) \( b3 \& v $this->db->setModel($this->name);
! X- e0 u; s3 ?/ Z, F' Z return $sql;
0 @% c6 d( \2 F" {; F, H }2 ^/ C% O% d" V8 s. e2 O
: \2 ?: Q# g& M8 T总结:
7 V6 C; M7 \) w5 R" ^6 x/ M8 E3 O不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
, K. h5 H' H- R* h4 W不建议直接用$_GET,$_POST3 f9 C' @* w' h/ g3 e# D2 s
[/td][/tr]8 p* _( n8 K' e* Y, g+ P9 ]; N
[/table]+11 s% Q2 A- S0 U/ E, i! a& H
% Y2 }! T! b4 g6 ]8 ]
' d9 p- Q, n! o7 k |