下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
! t) |$ _ k& x& T. k) P* `. ]6 CThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
+ W% {% C% S5 S& H6 l5 m0 L+ [根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
- a7 p' D! v. h4 `, e7 l2 @ Y0 i G! C使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:" I5 x) m/ m; I' @# _" q+ p
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
: m1 g" b% }2 ^& I( Q" r
2 t: [; n) w* r! s" i 或者9 |4 M3 Z; s1 x: c. J: y, a
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();" d5 ?; A& w, ?3 L/ ~3 Q1 O' j- z
( U9 J) N4 D% k. {+ H) Z' A, F% b
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
H' ]* M; X) E0 s$model->query('select * from user where id=%d and status=%s',$id,$status);0 T b+ l& ~3 q- K. ]8 [
: y, M$ K& d/ r, \或者6 V+ z2 t1 j( Y, X
$model->query('select * from user where id=%d and status=%s',array($id,$status));" B, p' @+ V G
1 m* y9 f- }4 Q6 b6 k, _2 F
原因:9 u# d1 V ~9 P% B
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤." I5 a& _( e$ B- S/ B
原函数:
8 G6 ~- V v3 u! D0 e( Oprotected function parseSql($sql,$parse) {
2 y& c* A1 z: Q* p5 y; Z // 分析表达式
' J+ V$ P- y6 M% n3 H0 V if(true === $parse) {" |( ~8 A5 P! x8 ~# o) r- i9 M/ K
$options = $this->_parseOptions();1 ?8 p" a; R0 r8 Y
$sql = $this->db->parseSql($sql,$options);
9 e; S: [' I( o- Y T }elseif(is_array($parse)){ // SQL预处理
, |8 X5 M" I/ p% j0 o $sql = vsprintf($sql,$parse);% ?" b6 c1 o/ e! }$ H
}else{
' b" i7 A$ K' q9 R6 \ $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
% n2 t6 r) r' I; b5 S/ d4 b }* N, I* X$ u2 H! Z5 t% I4 g
$this->db->setModel($this->name);; O. @+ W! r0 r4 Q
return $sql;" A. g/ J N" m
}
1 M1 C+ \; \8 t) H9 W# k! C) Z$ @1 r* B2 ]
验证漏洞(举例):
, T+ A0 f/ [' z请求地址:) F& Y1 t! X$ M4 R: r! [
http://localhost/Main?id=boo” or 1=”1
: v1 @" k; R& q7 Z' V或8 n5 J" q1 X& S- y2 i* P- ~* z
http://localhost/Main?id=boo%22%20or%201=%221
! }6 ^( {# [( Y5 T+ W3 ?action代码:' t, j% }4 }. Z5 X) I8 B- S- _
$model=M('Peipeidui');
: _' d. Q4 A2 h3 m' J: a$ g7 |- S $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
9 g5 D2 W9 U% Y' Q dump($m);exit;
' Q3 x+ b3 n6 O4 d或者; Q- Y2 L; @ Z8 a0 a
$model=M('Peipeidui');
7 N- S, K9 J E) e% A: Z $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
; i. E7 Z P* j: i6 z* R dump($m);exit;
4 g, x$ E+ B/ ]- ^' I: N- w- b' B' }2 E结果:
+ J" s: d8 c) }8 m7 O表peipeidui所有数据被列出,SQL注入语句起效.3 H0 d' x6 Y0 D
解决办法:8 @! Z9 y. J3 y+ X, [
将parseSql函数修改为:
0 f8 n2 ?1 Y& f; A- U5 K/ U$ I1 ~" Vprotected function parseSql($sql,$parse) {& r3 V+ Q& Z# n! I# r
// 分析表达式
' z+ E3 T- F( y$ O1 y if(true === $parse) {! I% l8 e7 Z- u; U7 g& `
$options = $this->_parseOptions();
8 g/ i, N9 b7 {7 |* c $sql = $this->db->parseSql($sql,$options);
4 V* q# D7 ^7 @" O/ Z3 _! j8 M% r }elseif(is_array($parse)){ // SQL预处理2 Y# ?2 B% S% Q- {
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码* Q( {* x. U, c+ n8 Z
$sql = vsprintf($sql,$parse);) d B% ]) g3 i' `
}else{
' f/ E- f& s* z1 b $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
% t9 @. K& I: L6 ]' t+ d }& U9 c' n- K8 y' p
$this->db->setModel($this->name);
% H, Q7 |& Z4 m- F" T) k return $sql;" H$ O4 c" p: z: B H4 }: g
}! X7 S R$ A8 A# o
2 C+ B( @/ Q; u: z2 ^5 i% C总结:; Q3 J) U6 U7 r! v- q/ |
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查* m) X, }% o7 \8 Z b" B& V# x/ K
不建议直接用$_GET,$_POST
* J& A% ~! L6 K% L M& y& O[/td][/tr]
1 ~; e" j& r: L/ C1 E2 W[/table]+1+ E. f" R- W9 L1 S. A/ V( O
( Z7 h" }- y2 q, }5 t
9 r# _; b2 r( S; u/ ~, j U8 @ |