下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。8 g: [" _0 y8 P+ R5 o$ @( }! I7 F
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
* I' p$ a& r; v) X根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
$ ]* s z% R" N! \6 W8 u使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:. k6 ~5 j0 [$ m& _1 C$ E6 ?
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
3 ]1 p5 N1 h4 q6 Q$ \* v k4 z9 o$ @& z' X, F5 L! x
或者% @" t' `: J; v7 @3 E
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
2 V o# G! D% u/ l& C' c! {( R
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
]- G- a0 r2 M, c* p: s& U$model->query('select * from user where id=%d and status=%s',$id,$status);
8 t5 z$ o- \ s8 G5 I- O6 M' u' i% J8 V2 I1 m
或者2 x- H. a7 {/ A9 t' _" D3 d
$model->query('select * from user where id=%d and status=%s',array($id,$status));$ V5 D% G5 f" N
; B8 S0 p. u/ `) g4 \ 原因:; n- X. R a! e9 q" w1 m! J
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
+ o6 q+ O g0 p u原函数:
3 Y9 \, d0 N6 x% W& B9 R+ Vprotected function parseSql($sql,$parse) {5 u; G, c6 ?6 D/ U" L* ^
// 分析表达式1 q0 y8 m) _+ D8 A; c0 `
if(true === $parse) {
3 K; u: m6 D3 |, c% p $options = $this->_parseOptions();
* v6 ?; x! t3 o2 f* k $sql = $this->db->parseSql($sql,$options);2 R6 O0 P$ i) Q. M \0 {2 M! ?* y
}elseif(is_array($parse)){ // SQL预处理
$ k6 Q- L# |# H/ z4 q $sql = vsprintf($sql,$parse);
" p N h! h. z8 I( j8 g }else{) ]3 N: @* J( z, `( t
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));# \6 E0 f* i' o# q
}
$ C* f9 B, |7 c: @& b6 j, j $this->db->setModel($this->name);
% n; e/ G) I$ K return $sql;; _% ?7 ?' W* x$ I8 R9 B
}% L; T5 @( e/ g) c2 }6 |
, y4 [. b% j% h, }5 O+ ~0 t
验证漏洞(举例):
v" R9 p; O( ~# O请求地址:
2 b1 R5 Y( Y$ ]5 C6 g5 ehttp://localhost/Main?id=boo” or 1=”1
0 @. m( }! g: B9 I或% E4 w$ P3 N2 H* S5 r% ?: z! [+ W8 q
http://localhost/Main?id=boo%22%20or%201=%221
8 h6 [! X) F# f. B5 a9 daction代码:
/ [; f: d+ G) l3 F# Q$model=M('Peipeidui');8 Z9 y' v. V1 a5 Q4 Y
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);8 m+ X* |' E+ O. ?
dump($m);exit;
3 j& w5 U, K0 f. X9 F或者 e3 K" d q# c( S; l" d' T
$model=M('Peipeidui');
9 |) ~( |8 Z5 n7 \ $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));! V y8 ~) Q1 m
dump($m);exit;4 ~2 z* S% e" ]$ u/ x# n5 O. b
结果:: [# o/ E1 a: M# s/ Z
表peipeidui所有数据被列出,SQL注入语句起效.
( @: V4 H* \7 H1 F2 H解决办法:
2 a/ t+ |! B: c: S. g将parseSql函数修改为:
3 g; l6 q, L- U( [6 T" R: Yprotected function parseSql($sql,$parse) {
, E* S7 O( p- d1 u- T: n6 t // 分析表达式
9 u+ }7 y( i: k7 i ~ if(true === $parse) {# i" |! k, _+ S2 f) M9 X
$options = $this->_parseOptions();
% ~0 P9 X9 f7 H: g' c) K9 ] $sql = $this->db->parseSql($sql,$options);
6 V: y6 `# j( B }elseif(is_array($parse)){ // SQL预处理
$ t: {4 r c3 y. b5 ?9 Q5 S $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
2 \% |/ E8 `! j f: S# l* J$ y $sql = vsprintf($sql,$parse);
7 f: Y$ x2 [) n3 U }else{4 o3 y6 O1 ^( e) h$ g8 M/ M
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));- L* b5 {! E2 _2 {& L( J% Q, A& a8 {
}- _" I$ }& l4 k" }
$this->db->setModel($this->name);
g7 [& O+ T4 J5 M [. A return $sql;
) A- h1 d+ h" R8 K* `/ u }
. t& f" J) \8 b% q: I& _. Q& M; x% X+ w7 J2 x
总结:
- `+ s% x4 U/ p9 S$ ]5 K不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
- R3 G# W, ~9 h5 X% ]- O, [不建议直接用$_GET,$_POST& Y+ x0 _+ v3 y. U' Z( v
[/td][/tr]* l* ] u6 V6 L$ i6 @4 F2 T
[/table]+1
) U4 n$ \$ u2 @5 R5 u6 ~( l) r6 ]% B6 Q# [5 K+ x1 R8 M' j
- ^4 ^7 ^* z8 C5 p7 ^& u |