下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。5 ]" s& b% j8 R; d
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
% o4 F# p8 j' q5 O1 P3 {6 \根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)/ o* c8 p! r! G9 ?
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:$ v) g n$ K9 D9 ?. X0 e
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();+ D7 d9 F: t1 q; H( Q9 S
/ M9 S7 [3 @7 Z( U: v; m" a 或者9 o4 ^# y7 q! d, O8 N, R! y7 l0 m
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
% V0 X( q5 B9 j- q \, M
: w& }9 w* e+ t' I( R* u 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):2 ]2 d2 |3 L- ` y
$model->query('select * from user where id=%d and status=%s',$id,$status);( f8 T0 d* K, c5 d4 U1 G
7 L# F; l0 V" N7 r* O, i6 {& k
或者 j A" m/ j2 _4 j# e/ J! x2 f5 p# z K
$model->query('select * from user where id=%d and status=%s',array($id,$status));+ v$ U% c# L( Q% T4 _- j, T: R
) U; Y0 }+ H$ I. T R! Z# _
原因:
! `- _, _+ ^0 {! E, i, o! ~8 z, hThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.1 y: V' L5 Z3 T* x
原函数:
. x# M% R6 C, h8 W7 a: iprotected function parseSql($sql,$parse) {
/ M8 N# a# k" M // 分析表达式% R' h {+ y; r' u- x1 d
if(true === $parse) {; J1 ^9 k8 t9 |& b. _" d5 `* b
$options = $this->_parseOptions();# @: X: E2 }& ?/ g1 i3 x6 g
$sql = $this->db->parseSql($sql,$options);
) F# S0 S W- f! i- M$ S }elseif(is_array($parse)){ // SQL预处理
/ d$ `% W" d/ c" g* y7 b $sql = vsprintf($sql,$parse);
' Z) L4 e/ h2 v7 c0 Z; v }else{
( \3 W! L2 J4 ~* e( e $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));) {) T. w- a7 a# Y5 @$ \0 j
}# i7 A7 O0 ?- [# ?+ X# \. l
$this->db->setModel($this->name);
$ F- @2 y2 C. b, q return $sql;
# M; N1 M4 T% J) E; O }1 g: b6 Y. v$ R0 z* N' h. W
9 a. B$ I5 Q4 L9 @
验证漏洞(举例):
1 L G% J+ O/ ^请求地址:9 Q O- r4 c1 A3 s7 h: o4 ?/ u, }
http://localhost/Main?id=boo” or 1=”1& @9 X+ M- ]" d$ S9 K, a. w' T
或6 F. o) s2 R7 ]8 C3 D0 n
http://localhost/Main?id=boo%22%20or%201=%221
1 V5 ~) Z" ?/ I) p' A6 {action代码:, i& P" @0 {) m9 G# P3 Z m+ r
$model=M('Peipeidui');3 l P) }( j9 B" _
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
/ D; b5 `- x# N8 C3 y# C dump($m);exit;
$ T6 |" s7 @5 M+ ^4 k或者
( I8 ~# O% s: b. ~8 D* N! c$model=M('Peipeidui');# N5 K4 o7 d* d/ E+ Z
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));# Q" s& ^- W0 D: N7 \6 x! H
dump($m);exit;
' u7 G9 }* H# R0 u/ k- a结果:
6 |: X) x2 T* i/ |% Y/ C" V, `表peipeidui所有数据被列出,SQL注入语句起效.6 t8 y4 ]% U7 F8 p( Z( R7 R
解决办法:
2 {! F% F8 M6 A* _将parseSql函数修改为:5 P. Y+ j) o$ L7 J
protected function parseSql($sql,$parse) {4 \& m* ~7 P9 R/ r& V. U% t
// 分析表达式
$ J b% J2 D7 u/ i if(true === $parse) {
+ w2 v5 M- L3 [2 t; s* o $options = $this->_parseOptions();% @- T H7 q3 R8 S# i" {3 }) @2 F
$sql = $this->db->parseSql($sql,$options);* s6 Y4 y% ]0 y3 K0 s% c
}elseif(is_array($parse)){ // SQL预处理: n/ ^% A% z1 t+ q0 l6 M+ y
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
2 q, t7 O7 U# ~ $sql = vsprintf($sql,$parse);% C- |9 X+ D7 H3 ?8 j! B
}else{2 ^3 t$ w4 Q! S V2 v& {& F, t
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));' e6 n# I4 P2 C
}: T8 D+ h& T/ w* K* |/ {, i
$this->db->setModel($this->name);. y& b& q, ?: x c# N( y
return $sql;
$ f7 r; s" d' U& G }
; u( M$ U5 F5 x0 u8 s, C
8 h6 H0 O4 f9 @总结:# d# j/ k4 R9 v
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查; f: {/ u3 f8 Y+ G+ o: K+ d5 v
不建议直接用$_GET,$_POST
+ v6 d8 X7 t0 A[/td][/tr]
2 i" I Q, L8 n8 a2 q: w[/table]+1
+ t, U/ L/ `6 d4 y* w/ U4 O1 m% W# T
' s$ Z* L& u5 C# z0 H+ p- n2 b: y* D2 \7 Y
|