下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
5 n% Q: k" |! [; |3 J a2 V' dThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
! S2 ~4 U9 G! l8 H5 B5 u根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)0 h+ W4 M4 R, q
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
& G ~! D, C5 E g) {' \/ Y& Q$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();, P Y0 f; |2 h1 W8 p
) D N# c+ m/ ]/ R$ T- K& q( ~% ~
或者, k0 ?6 A o6 `5 x5 f$ N* s5 W1 _
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();( a0 B: u* `+ T9 y. l0 {2 l
( e9 r8 g' m# k2 m
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):( Y1 g# d" M3 h2 \
$model->query('select * from user where id=%d and status=%s',$id,$status);
% T: K( _7 `* g- M$ D# {
, a8 S- I- Y6 @& A' h8 a8 E- s) J4 J. i( \或者
/ N: A0 }# z* F+ @/ I- d1 L$model->query('select * from user where id=%d and status=%s',array($id,$status));1 p/ v( x" _- K' o# B$ i! O
0 L4 N! r% n* S$ W4 s* V- W 原因:4 N' }2 M" o& m8 y9 C3 K8 a7 a m
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.: G& U& e3 P+ O# G4 U" p
原函数:8 ]5 ^/ ~! z- k6 t. H/ @; l
protected function parseSql($sql,$parse) {
- B8 x& o. N# x( K' R7 h/ ~8 E/ @ // 分析表达式
7 F# m# v! p. O2 X4 R if(true === $parse) {
5 C# ?5 _. r R5 E8 |- {; P/ z $options = $this->_parseOptions();* Q+ D: v3 J! W
$sql = $this->db->parseSql($sql,$options);& t" G- Z0 l" f8 C- }' D
}elseif(is_array($parse)){ // SQL预处理2 [- g% r* F3 _6 r R, K1 ]
$sql = vsprintf($sql,$parse);
( W9 k2 ^7 a* M }else{/ p* s" u4 q: t% O. j+ b
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));: a6 q- W3 ?* T6 ]9 G8 N
} f4 @, D% ?* W( z2 m9 _
$this->db->setModel($this->name);6 D. v) X; e. c' E+ j
return $sql;1 v) d4 V3 I9 p$ j% T- H
}& z3 r2 Y9 d4 Q
% h! V7 _7 u0 F, d3 c
验证漏洞(举例):
2 @% X% P7 e) B3 X; G请求地址:
+ A0 c) m V0 n9 _, Ehttp://localhost/Main?id=boo” or 1=”17 D/ d+ G* ~* I p
或3 e* V/ h+ G6 U) S7 l0 v/ m
http://localhost/Main?id=boo%22%20or%201=%221
( i( K: o4 @2 h* z9 Faction代码: R/ e$ S8 E' q5 x. ^* x: ^
$model=M('Peipeidui');, s% @* N- v* u2 Z8 ]
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
+ i9 Y! A6 N6 l, H+ |9 i dump($m);exit;2 E; ?( t) L# J, w4 w
或者0 s Z( D/ X1 A4 ~2 L+ o* G! d1 p% C
$model=M('Peipeidui');$ Q, S* E; B* H+ M' Y8 d
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
7 x% `. d; ~% F6 r( g5 y dump($m);exit;* [' K! y Y; V6 p- u
结果:( c8 U3 T' Z4 T" a( u
表peipeidui所有数据被列出,SQL注入语句起效.) _2 q: r, x5 D. u! J- Y* V
解决办法:
1 T( a/ X' U2 H6 [: ?将parseSql函数修改为:
( O; m5 T' O. B: C2 sprotected function parseSql($sql,$parse) {
- l) I' l3 [ K; ?* w // 分析表达式, K( U: |2 u% r4 L* T& ^7 ~# d
if(true === $parse) {$ M$ E# `* C6 O0 U# o: V2 O' Z& f5 B
$options = $this->_parseOptions();
; ~1 f- h2 W" d* C7 C+ Y% T5 R: Q+ m* U $sql = $this->db->parseSql($sql,$options);
6 R2 m: K& q6 {0 K; ~# w7 { }elseif(is_array($parse)){ // SQL预处理
& W7 i* T, O0 A) N, U $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码" S- U( Y/ q2 H4 J+ Y
$sql = vsprintf($sql,$parse);; J+ Z# \ y0 G' m+ O f7 w
}else{+ Z" @$ E: O( I) g, ?& s; Y' t8 d; Z
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));5 E; K) r& c9 ~& D
}
9 }* ]) d0 {) S: A \ $this->db->setModel($this->name);
) g4 r+ K5 U& @ return $sql;- Z- m; m: k) t" r/ i2 O* Z
}1 K; k; n K& R. f/ L. i
$ \& V* }# ?& d) b0 U总结:
+ B( A) |1 ]6 H$ E1 s! T不要过分依赖TP的底层SQL过滤,程序员要做好安全检查. r4 l# L1 H9 ~, l) t+ v
不建议直接用$_GET,$_POST1 a, g) B* o% G7 k2 ^
[/td][/tr]
2 C7 z& {3 y. ?5 L* R- f[/table]+16 _2 g/ `! e0 b1 z+ v
$ o1 @$ E7 H6 K1 x1 a) L' Y4 h
9 C, ~5 t; W/ | |