下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。4 j, P @, E: V9 M( M4 T
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
. [ F6 q Q% U L# g) j8 ]根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
: u# L- z4 o* b9 V6 s9 Y+ A: M使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
' I4 n- [2 n3 V$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
; j& c( h9 K) o/ Q. @
$ l6 ^1 P! |1 y9 J* a 或者* \* l$ K, E! g/ s; F+ W
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();% Z& g+ {# r, H. U
6 U9 e4 U! g3 }+ M4 z- L
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
9 D1 a% q3 ~5 R$ d* d3 o$ | o$model->query('select * from user where id=%d and status=%s',$id,$status);
$ |) B( p, X1 ^6 g" o' D7 ^; ^8 E7 r% k1 @/ z1 T, Q% ~* s( ?
或者' ^% }: ^- C' ^
$model->query('select * from user where id=%d and status=%s',array($id,$status));
1 K; S' r* D$ Z7 D$ \& \* v0 A6 t% T. f$ j
原因:1 ?# ?2 W" f: U: N
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
- k4 E* r @. ~0 }% d8 H* s2 y原函数:
v0 ]0 ? s9 D' [7 sprotected function parseSql($sql,$parse) {
" B5 g& |* B1 l7 N( C- K* a // 分析表达式
: X- h* |. ? L+ ~+ { if(true === $parse) {4 I4 A- w9 }6 t# R0 v0 H }) U4 W
$options = $this->_parseOptions();! v6 N' w, c. A4 ~. c
$sql = $this->db->parseSql($sql,$options);+ x8 {/ A: y9 i5 h& f7 R
}elseif(is_array($parse)){ // SQL预处理1 q. R( S l, g/ d
$sql = vsprintf($sql,$parse);
( W& s. _! G( N4 M$ _: i0 ~; W6 v }else{3 p l( {" V) g" a& L: @3 ^/ [
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
& i$ m" f# d* q0 h# C$ ]6 l }" o6 {6 k! \9 z* ]. G! E
$this->db->setModel($this->name);
% }$ E( Q0 r/ i2 {# g1 n6 J. t return $sql;* S4 H6 c& A: F
}% ?; P3 F y3 _9 D
( [ Z* \9 i% V3 P8 R% o/ G. t5 H验证漏洞(举例):
. a1 t. k6 k, t1 B8 {/ T请求地址:
( E4 E* t, s1 Khttp://localhost/Main?id=boo” or 1=”1
- \, b6 ]7 G) O- }; b. _4 j或8 W1 K; V! c4 }! l4 H, j% z. J
http://localhost/Main?id=boo%22%20or%201=%221
& S; U; y4 U( k8 h# H6 aaction代码:
5 F& O: a" w1 A4 v% U. M$model=M('Peipeidui');
& V. W! L5 ?( ^* c" @$ H1 e- d $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);& v4 g& ^; p, [9 T
dump($m);exit;
' S5 b7 J& Q% b4 |5 c4 R% N或者
9 }" U5 t% G2 \- Q$ A4 k$model=M('Peipeidui');
- y. @' V0 ~, V4 x' W! A $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
% j- b7 b4 v8 X, \! S dump($m);exit;
! A; Q" g( L0 g/ D结果:$ E9 j1 g' H+ ^3 t
表peipeidui所有数据被列出,SQL注入语句起效.
R. i( y; e0 O' {& ^3 H; i. @7 ]解决办法:
. \% V$ _* P, G9 J将parseSql函数修改为:
: v4 W- O2 V0 T" P& y% Pprotected function parseSql($sql,$parse) {- r# V; i3 _7 s- X
// 分析表达式
c/ d: n2 R6 b7 E7 q5 q2 c' U if(true === $parse) {
1 z4 y. D7 L1 C# O' f $options = $this->_parseOptions();, h" h: W& Z( t% |! K7 O# Z
$sql = $this->db->parseSql($sql,$options);
2 `' t; m" k" Z( P S" M' Z" X }elseif(is_array($parse)){ // SQL预处理
# V# C+ ~+ U! {; Q& X6 T3 G# `9 ? $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码$ y" X8 w: ?8 K5 U8 D" U* k1 X
$sql = vsprintf($sql,$parse);
2 S6 ]! ]' O# l# O. L$ J }else{* g5 a# F6 X2 _$ r+ r! u
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
5 \# {) H% X8 L/ N1 P }
+ y4 o4 L! n) h) v $this->db->setModel($this->name);: v5 k- n6 H4 q( [ b' T
return $sql;0 t4 G4 s" E! t& F. s! D% _( ~
}5 p3 K0 j5 a) f+ z
* o- ~9 |* W. m8 u$ r0 H总结:
* @- u+ r- o; w; ]2 C: ~$ V不要过分依赖TP的底层SQL过滤,程序员要做好安全检查+ [8 Y) a _: w1 J' T
不建议直接用$_GET,$_POST
. K2 D8 t! T x+ R/ g2 \[/td][/tr]7 f& U4 s% z& J, ]
[/table]+1
6 G# I# F- E$ u9 o+ ]6 J, K9 z& b" M1 b. j7 r0 ~
5 W- z( h1 @7 P+ h1 r |