下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
1 J# P3 H0 V' Y# z: [ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件; o" [$ }3 ~3 x& [. F% ?
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
+ W% z. L1 o2 U2 n- ^* _' t使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:+ o4 z, ^" Q, z: i! o# k
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();) Q' n# C8 c) T/ M) L$ @, y
: j$ J2 ^7 h" H/ ` 或者1 [3 u8 e% a6 T2 d5 Q5 M
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();2 d; n3 [0 Z& R) ~
7 T2 O3 m7 W7 s* \ 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
$ B1 [& W, F, J2 N$model->query('select * from user where id=%d and status=%s',$id,$status);! w3 D# }$ Q5 Q, K
7 A% A% E( P X7 n或者* B# o1 Q* B1 G& F! x$ B
$model->query('select * from user where id=%d and status=%s',array($id,$status)); L: D- d* M( L8 I- i M+ V
$ ]) L( I; L( Z) ^1 X' s' m 原因:4 }( @6 t' v; { D: @: M
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
$ F$ T3 y8 E( e, |1 S" o7 @+ y% y原函数:
k9 r. ] d6 n6 v+ ]/ v' d/ ~protected function parseSql($sql,$parse) {
3 B) Z2 f1 T" n8 C! i0 B% @2 n# b // 分析表达式
# n; v; C( l M6 g. E( c if(true === $parse) {+ O3 ?& f, m3 Z; ]" `
$options = $this->_parseOptions();8 W, Z: o/ V) G& ^$ X* p; v5 m
$sql = $this->db->parseSql($sql,$options);
! @5 b6 w9 F3 E+ I6 P }elseif(is_array($parse)){ // SQL预处理
O9 S6 t$ g T) x: g+ s $sql = vsprintf($sql,$parse);+ G- H: Y; Z$ w! C6 g
}else{- B+ M, i" R, a
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
. i$ v" n* E( l R$ | }3 E8 C; ?9 J, x! K: ~5 a' j# n
$this->db->setModel($this->name);; ?- w1 D7 d( ~! x4 Q
return $sql;/ {% K+ M2 \! o1 d$ A; T$ a
}! @/ y, R* f# V+ x4 K. I0 n
/ Z9 c& A0 l- e) o" ?验证漏洞(举例):
1 l* \# V2 f3 T8 ?请求地址:0 r: t+ a3 H! w- i, s
http://localhost/Main?id=boo” or 1=”14 y+ j7 {: [3 a
或
S% W* M3 G% Z3 Z8 O6 G6 I6 }2 jhttp://localhost/Main?id=boo%22%20or%201=%221& ~1 C. f8 ?2 v) w2 H3 n/ h
action代码:$ q7 g7 {" h3 \* Y( T, ~1 ~
$model=M('Peipeidui');# _- t9 p3 l) p; T: y
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);3 t4 W. C0 Y5 d& x& D; G
dump($m);exit;
% V3 T! Q6 A% L# z或者
2 Y! J/ A( S/ Q" ^5 P. G9 k$model=M('Peipeidui');
" P) o2 i$ o' r$ H: u% @. R $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));! H1 F, K8 i# ?; P0 C% {7 j0 m
dump($m);exit;
& }7 {8 b! k' q结果:0 ~' A+ B" J" c5 C" Y, D1 h
表peipeidui所有数据被列出,SQL注入语句起效.
4 y- ]' p4 m. N. ^. U v5 w, d2 i解决办法: l- \" Z1 {3 D5 c3 \
将parseSql函数修改为:9 j" [& w6 M# f
protected function parseSql($sql,$parse) {( }0 Y7 r; \$ h
// 分析表达式4 s5 t$ J8 H4 _
if(true === $parse) {
; P7 K! _# F: ^5 U3 C* p- V: w9 z $options = $this->_parseOptions();
, L! i# ^( y H h5 j! r $sql = $this->db->parseSql($sql,$options);! z8 U; _$ I7 A) M, p) |% d
}elseif(is_array($parse)){ // SQL预处理/ {) e* c) ~! Z# N% r; b& b s) M
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
6 @4 r3 a- i d% H5 i $sql = vsprintf($sql,$parse);
5 X+ h1 S2 a) ] k5 d6 n }else{
: h; C2 g. [, u) L4 M $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
1 z$ I5 D r& g4 t1 R a }
2 K5 W9 X# ]) d $this->db->setModel($this->name);( X( _ A9 K" h* w! \5 x0 [# w
return $sql;
3 ]1 N* A0 k* \) \4 V1 Q8 O }9 G ~# H# {& {9 [
# D2 ]& l4 g/ N9 P- v
总结:
: @ i# i# S9 ]; x& G0 e不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
: }% e8 P( }- E' P4 c( [不建议直接用$_GET,$_POST
4 O* {7 y! @ ~0 V* `' _0 W# A; E[/td][/tr]# X, Q1 ^+ n7 G2 f! @
[/table]+1
8 D% B2 w% i6 F& ]5 Z
) p7 W5 X2 X/ f- `' i, s' X) }3 K) e+ L
|