下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
+ G! u$ U3 r- w- nThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
6 Q+ M" `1 j; y; |* {9 ?1 a. i根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
- ?/ z# h% [1 B8 b6 D, u% c: S使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:1 W& \6 s2 O7 d( S4 y. S
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();" F7 k- B; @7 P) y5 b% X3 e
+ V6 Y$ b' V N% E4 I* I5 }1 g4 F6 C% B 或者& \! D8 o" b1 Z4 z: U) ~/ ]
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
5 X4 B5 Q6 [* e7 ?4 K/ S# U& y" u
3 N' Z' I g6 C6 Q Y1 F. G/ T3 X 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):2 f1 d4 ^- r3 S* d
$model->query('select * from user where id=%d and status=%s',$id,$status);9 e; B& h4 e+ k8 C0 N* T4 w
& P* Z3 q {. g/ j5 ~或者% P2 M4 V! A) l9 a* U! ^
$model->query('select * from user where id=%d and status=%s',array($id,$status));' \8 D# @2 F/ J$ F1 ]" B7 U
9 ]% V0 p$ P7 e. A; z
原因:
" @" O! T \4 l6 l0 V( W( HThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
% w! f2 s$ n1 _) y5 _原函数:
0 F* S" ~8 n4 M! R. Fprotected function parseSql($sql,$parse) {4 ~* H, ~! d* f4 O, N
// 分析表达式
4 v- e" j9 z0 F5 } if(true === $parse) {
( o4 W" t m4 Q: A! A' G$ B $options = $this->_parseOptions();
, x; r/ x$ E) d. y* ~. l; H" l $sql = $this->db->parseSql($sql,$options);6 R* Q: E& k- M8 h
}elseif(is_array($parse)){ // SQL预处理7 t* j' P( d" M& x0 J& s
$sql = vsprintf($sql,$parse);+ _# I* p+ n5 _8 c: C
}else{
% V, a$ y J4 x; u' X: u9 } $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
+ ?7 B$ `( Q+ K# ?; \( s; x5 R }
1 v4 n1 t0 }; i) z! Q: m $this->db->setModel($this->name);, V, ]" v, H5 m8 w o2 `+ P) ?
return $sql;
9 N5 _: X$ F3 X) h7 z }/ V/ g' Y4 R9 s+ Y5 j' g7 A
# Q0 H+ _3 V | Q2 f# v. l验证漏洞(举例):
. s: o9 i& \3 H1 y1 C请求地址:0 L0 J! U+ p* k1 Z4 h
http://localhost/Main?id=boo” or 1=”1% G' J6 d2 i3 ]) e7 B' m4 a! o
或7 P% S8 B/ o4 @) `) d' l
http://localhost/Main?id=boo%22%20or%201=%221
( X* G% M0 m9 k# Eaction代码:
5 Y! G! m& k( ^4 ?8 G! h, F& r5 K$model=M('Peipeidui');
. M8 @7 X6 {: f o( ]; P6 a$ Z9 o $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
& _3 D, y4 b I4 f dump($m);exit;) z! ^2 O" T8 H- D
或者
$ B; V6 J9 u" I7 q7 U+ y$model=M('Peipeidui');
2 |; x* q( Q( f $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
2 l# O' a, U9 s7 B) e3 h dump($m);exit;( |/ x/ ]( `# _8 v0 a) Z; H
结果:
# m z( I$ v+ j3 z# R表peipeidui所有数据被列出,SQL注入语句起效.( C& `6 L% |% Y8 m% h% _
解决办法:
8 H2 s7 u5 s$ d0 w将parseSql函数修改为:6 h( z1 c; K% P" c' U7 s7 T
protected function parseSql($sql,$parse) {& S/ ~9 q, |% C* k8 K* D
// 分析表达式4 C4 i" _& j( l# F8 g
if(true === $parse) {6 d2 h( S* p% a9 N8 E# m
$options = $this->_parseOptions();/ K& Y O1 Z$ e- ^! l6 t" w, f$ h' q
$sql = $this->db->parseSql($sql,$options); X" N( z+ D3 w
}elseif(is_array($parse)){ // SQL预处理
$ O1 v- ~3 c9 [; Y) ^) v $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码- d" L( i- I- T! Q, q* `
$sql = vsprintf($sql,$parse);
: u+ M) m2 ], v7 J- l* ^0 q }else{& q" V- y4 z% z2 ~2 n& V5 W: i
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
/ W+ {# g; b4 K' ?8 Z! Z }6 s4 g6 y8 m2 i
$this->db->setModel($this->name);
: [; Q& l* l1 y" Y8 U* c3 E, t return $sql;
1 l# Q+ l: L% v; `2 O" j }
3 T) A' D% t: |5 j& \1 |5 F: t! ]& S2 m9 ^3 J! g% H
总结:
# T. s) y- z- I0 T4 |8 R' |. n不要过分依赖TP的底层SQL过滤,程序员要做好安全检查) x& ?7 F4 V x; n& X. \& P
不建议直接用$_GET,$_POST3 q, m8 C4 c0 l. S
[/td][/tr]' Z# _, ]8 k9 d: U% i
[/table]+1
{' c- F. Q0 |3 ]
3 t" w1 d; T' H% |$ ^/ w( j! o0 M+ X. S, [5 y# F( x+ x
|