下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。0 {. Y0 X$ R# A K& ~" K
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件9 x% G+ `& u- Z4 V
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
# M4 z) c* n) _4 C1 k1 r/ `使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:! U8 ?0 O5 v1 H& Y$ |. c( T
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();: O% m7 X( A S# Y
1 e6 q0 p1 c$ T/ R) }% k/ y
或者
" c# X+ R3 |$ @ w$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();* K$ A5 R6 H( O, D& F
8 V$ q4 [. c( g 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
8 a: E0 g, B1 T, i$model->query('select * from user where id=%d and status=%s',$id,$status);
( `; M4 k# e1 }* u& M$ d2 ^# t- o# S4 M& W
或者
3 j8 U9 B( K5 ~( X9 T$model->query('select * from user where id=%d and status=%s',array($id,$status));
, _& i, a$ F' z: Q" \9 P' d
8 P- @9 d# S/ R; G: O0 g3 { 原因:. E# k5 L8 T! w0 M9 U
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.- Q% R4 h' E. ]; ~) v% i
原函数:3 m8 ]; t: f, g# v" }' h
protected function parseSql($sql,$parse) {
6 B( l& n! P5 N; V/ q# ]" s2 N // 分析表达式
) C, X3 Q0 J. Z' } if(true === $parse) {
7 K; }, m1 G0 \; v l+ \6 k $options = $this->_parseOptions();
1 g9 q0 w, B! ?# Z6 n A8 c $sql = $this->db->parseSql($sql,$options);
; s g6 R2 h* A$ @: E/ h# L; a }elseif(is_array($parse)){ // SQL预处理
! ]6 ^5 u8 ^8 {5 H0 F. b8 O# o $sql = vsprintf($sql,$parse);
) f: \' L {* t0 g5 B! t }else{
( a. G# P' t6 l5 Z- \- J- q# v $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));2 w$ v# w/ _) ?; Q2 N
}
( V# O( k0 C6 i) p& e' V# W0 T $this->db->setModel($this->name);
, |" p7 l9 W! b# P return $sql;
* F3 S* \9 J& ~2 o; k3 f4 B, _ }: T. z$ ^# j+ D! T# O& r m1 x+ J# ]
% C/ ~: M8 z1 ~3 ?: _0 P3 d2 b
验证漏洞(举例):6 V& x+ ]8 s; V( d
请求地址:3 K3 J9 y G% }% Z
http://localhost/Main?id=boo” or 1=”1
8 [' h. F9 S! {- C! n/ @或: i2 p: K& d0 @! o7 a& K% R5 c
http://localhost/Main?id=boo%22%20or%201=%221. Z6 H! {( ]$ b) m, u5 M* G! {
action代码:
+ N) R. J9 o B0 _5 @' o b* T# _$model=M('Peipeidui');
' f" D& U, c; J# I& x $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
$ [, R: h6 ^8 W( n) A) F" e dump($m);exit;
, W& e2 O1 A' v1 l/ t) o' {或者
* k6 A5 S' ~! C% h! Q* X$model=M('Peipeidui');
: H( }' L8 z% J$ b5 q" A$ E $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));+ J( L2 ^# Q: K" ~
dump($m);exit;
! I Z1 L; s# I% S- x( a结果:5 L/ V7 t$ T' b( W
表peipeidui所有数据被列出,SQL注入语句起效.
5 I/ p6 R- I7 {5 ^, G7 x# ~8 `解决办法:; O* D. T2 [( u' K
将parseSql函数修改为:7 @& N8 `2 Q) b$ X+ `
protected function parseSql($sql,$parse) {
) U2 P9 G, R# U" N" Q) Q // 分析表达式
! y" ?$ r- l4 p4 `# o$ C% f1 k if(true === $parse) {1 N/ u8 E7 i6 n' L% j
$options = $this->_parseOptions();) u, e M1 G6 D
$sql = $this->db->parseSql($sql,$options);
5 {# v" Y5 q. {6 U/ H% W }elseif(is_array($parse)){ // SQL预处理1 K8 p$ n9 p3 }6 A+ {& @8 [
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
0 _1 l# o& s# U0 c# L" `( x* o. ? $sql = vsprintf($sql,$parse);2 Z* U, t* `/ {* Q
}else{$ }: W8 Z9 q J& w/ C J+ y9 d
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
. S$ Y, l: D9 A. c }
& g8 K' O7 D" ^7 x $this->db->setModel($this->name);
6 a# C% D% L. D d% ]$ i- f* ?) o: U return $sql;8 W6 c8 F6 Q% E& i9 R4 V
}
' l. t' H8 v; T) b M
: M, d* |8 U/ g总结:
+ ]$ Y* S& m# v9 `& i2 u) X8 X* z不要过分依赖TP的底层SQL过滤,程序员要做好安全检查5 Y0 a' \$ m+ l6 p+ l: S* Y
不建议直接用$_GET,$_POST
) _5 v/ m% t- E7 v[/td][/tr], C$ C- B$ e) w4 d
[/table]+15 X' t9 [9 A3 i O1 d( c4 W
( i" B# `8 R% K9 O7 Q
n6 N8 y+ b6 i. y! g9 o) U7 A1 P& u# e
|