下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
/ r% t; y+ R3 w8 jThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件1 V; o) e3 y9 z8 v
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)& W8 p, } c4 n H- L2 F) q
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
" `+ a2 Y1 p4 I3 j' v7 e$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
/ O# \+ r. v1 E& _9 S1 ]4 D% N
' S/ Y9 M& B/ _! S. Z6 [ 或者
/ u1 a' X: X7 y+ y V n9 d0 l; Y% N$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();; Y+ B, W4 R; w; T; B
0 S7 Y* Z# H+ K. C4 E$ [* |% k
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
" h4 B! W h8 l; _2 q7 c1 ]$model->query('select * from user where id=%d and status=%s',$id,$status);. v! R: X3 t0 Y
, r8 ?% y. l7 F p8 |或者- i L8 D% h6 S4 g% E" C
$model->query('select * from user where id=%d and status=%s',array($id,$status));3 v- M. [ \" C/ b
& K. W( @& w+ [* d+ `8 \ 原因:
, [3 [; w6 @* r, u6 EThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
+ n3 y. q8 {; n, {0 z原函数:
6 i" Q% s$ ^( j) m, c A- ?) J8 ]5 z4 sprotected function parseSql($sql,$parse) {6 j& B4 u( s9 q4 g
// 分析表达式
5 ]% M( ?' O9 r if(true === $parse) {. L% y: @" \; N
$options = $this->_parseOptions(); O+ {- U4 `1 w; S; y
$sql = $this->db->parseSql($sql,$options);
6 v% ~+ m" } G& r2 x- K }elseif(is_array($parse)){ // SQL预处理
8 l* d& [& \/ [# p% c $sql = vsprintf($sql,$parse);
# T- F9 Y, T4 m9 v }else{
+ |% i" d0 q k0 R $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
! |4 X0 e. O" V3 Y. U/ K6 _) \ } q% E7 m' B0 B8 [6 e% I4 c+ }
$this->db->setModel($this->name);
7 H" _' w2 c1 l8 C- L9 H+ a return $sql;
/ s6 ]7 \1 _; J5 Y }
# d) P/ ]# U: H( [ F$ f; r0 g. E/ G9 w- Z) ?
验证漏洞(举例):
) u7 d% u F/ [) y* \请求地址:% b' H9 |. [- [8 m; y
http://localhost/Main?id=boo” or 1=”1
' b+ T3 L: w) _9 Q9 X1 K9 _或
+ J. b) b c+ i2 y& S. |9 S2 G: K" Chttp://localhost/Main?id=boo%22%20or%201=%2217 S6 Z2 z i0 j$ @
action代码:/ J6 @( `) r: _4 K
$model=M('Peipeidui');% s4 H I5 Q7 x- W' r5 x4 i& {
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
: b$ d% B5 O: D. l5 p9 ?" U4 d dump($m);exit;% U- _3 u: P" N; [. i
或者
0 Z& q: V# t1 ~* }: {. y% N$model=M('Peipeidui');
% u' n \/ f. S$ O $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));) g8 {; Z$ U0 T2 R# W+ ~
dump($m);exit;
5 K$ Q& `1 f. n% q. S6 U3 A结果:9 O4 t" x; L* \0 A6 _. }
表peipeidui所有数据被列出,SQL注入语句起效.0 r( d$ Y/ P( C
解决办法:) v9 W' k" N5 G3 O6 ^3 o4 F
将parseSql函数修改为:
! |! d1 k; C1 {4 M8 Xprotected function parseSql($sql,$parse) {8 {$ x* n! @' w P
// 分析表达式
$ l# Z7 I, H# w# H8 G. b if(true === $parse) {
' t$ W" i) s! h) l2 [ $options = $this->_parseOptions();
, Y- `" [6 W" \) i $sql = $this->db->parseSql($sql,$options);' Z4 d- Q4 F1 K$ N, O
}elseif(is_array($parse)){ // SQL预处理2 `+ C* {1 X+ m1 v7 ^, U- [/ b
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
. s& J W7 t5 X; R9 I3 N! R- J $sql = vsprintf($sql,$parse); T0 L3 w6 R$ T" j& A# I/ t
}else{7 n8 c. h6 p+ B7 Q1 C9 |3 t) o
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));. \3 u3 Q9 U5 h' i
}- F" ]$ m1 R% ]: \. o0 ?9 M/ J2 V7 _3 y
$this->db->setModel($this->name);
% U% g. W: L' |# E return $sql;* n- S5 ], W+ @, x3 e% X
}) g0 C( E3 [- Q$ z+ U. x8 r
/ m: `0 \1 W+ f1 o0 V总结:0 r Y% a9 O0 T5 b2 l, e
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
6 D8 y2 Q( U( Z6 q4 g0 U+ {1 u不建议直接用$_GET,$_POST
/ a! r- F/ S+ k0 x- l& L[/td][/tr]
% }2 U' g' F5 }5 X. A[/table]+1) ^1 w2 u: J4 j0 |& Z
u$ R5 z9 T4 B( i& D# t! D' P: |
4 \: T- \: d5 ~3 Y! } |