下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
8 D Q- c; t1 P% i s3 R' v& S' j% h5 KThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件0 `7 C3 u# e4 u: [0 J7 o/ I! B
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)/ Q% l6 N. w9 D. N: s) a, O
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
, `3 J6 w' M$ F. e& W. J8 T$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();1 F3 y9 u! w4 a0 h
5 n+ ?7 d. M1 y; L, w/ q 或者
& R& A7 X- d' S3 K$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();: ]! t* s/ c+ U. n; p" p
2 ~7 Q) ?; `) h; ?; \# Z1 s 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
- n/ M/ s# n3 p3 a# ~$ Y9 W$model->query('select * from user where id=%d and status=%s',$id,$status);; l0 k* d0 _$ b
3 g! [3 l0 b3 [1 ?1 f
或者
^% x$ X# I3 O& o$ H8 g, @( \$model->query('select * from user where id=%d and status=%s',array($id,$status));" d8 c& u8 x% B6 F" ~
# \: ~9 O0 j0 h$ ]+ \3 p
原因:
. n4 R, p, a. g t! @) \ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
: _* P) E l4 ~# J! k5 n原函数:
1 ], A7 A! q. Y% X! Dprotected function parseSql($sql,$parse) {* z6 t _3 Y- W# `1 q) i
// 分析表达式6 m6 q0 {7 A0 |9 j3 u
if(true === $parse) {8 R: }% [& u$ }0 w9 l# [2 w6 [
$options = $this->_parseOptions();
O" y* \) M# x, x3 q $sql = $this->db->parseSql($sql,$options);' \) Q5 O7 Z! ]; T' S( C1 [& e7 K
}elseif(is_array($parse)){ // SQL预处理+ M7 l' r% S8 B
$sql = vsprintf($sql,$parse);0 m# }$ `9 ]; t/ ^
}else{
+ F, j5 l. c5 _ $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));7 k4 y# u3 }: J7 W
}
8 p0 F; l1 G( u% |2 I# h $this->db->setModel($this->name);+ k2 Q- D, y" S" ^( G
return $sql;
7 n' I- i. V9 y) V: s$ g' [ }, t* A1 ~, O$ O% D5 `1 R& G5 U! l
( _! o- C) H7 }0 c0 K6 z
验证漏洞(举例):9 t3 l) [7 l4 _3 l2 s: g% O
请求地址:
) F* s. I0 J j) u5 m9 r. Mhttp://localhost/Main?id=boo” or 1=”18 S( g! H2 r+ _. A# f% Y
或
0 k8 e. l4 D% mhttp://localhost/Main?id=boo%22%20or%201=%221' T V- X4 P2 h
action代码:7 V# V) \+ R" g! @- x
$model=M('Peipeidui');$ E: b4 x7 o$ x/ g
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
& E( s# ~' T2 y* d+ p4 T; T1 ~ dump($m);exit;. E8 ^$ L( `" I! s% \1 w7 Z
或者3 |, L& e* R0 U# z) n
$model=M('Peipeidui');/ P! M4 h& R! |$ e
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
& R6 Q+ ?- R4 N+ p) ^2 F dump($m);exit; I- H% o: P. o. {
结果:
, p' ]$ Q( H( n3 U3 ?- g表peipeidui所有数据被列出,SQL注入语句起效.
& o* b5 T4 w$ @! s2 T P$ r解决办法:
8 M4 a# P$ a) p, @5 O. j将parseSql函数修改为:
+ \2 C. w% [. X) j& [/ `& ^protected function parseSql($sql,$parse) {2 E3 o3 `! K2 W$ D. j0 p
// 分析表达式
' `1 H* p; L; x5 _. ?; Q if(true === $parse) {" M8 J! O& _/ w: A
$options = $this->_parseOptions();
* [# O; Y% f: N/ I2 y0 @; R# Y: } $sql = $this->db->parseSql($sql,$options);4 F; b2 |9 i1 V* Y5 r: Z
}elseif(is_array($parse)){ // SQL预处理
* c. a1 P5 h3 K' c I $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
' j k! o1 ?+ e8 {5 E $sql = vsprintf($sql,$parse);6 |+ Y5 S! a. v* V+ W8 J' |
}else{
/ x2 {$ t' F& p1 ~4 w $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));; ^! i0 p m0 ]( i1 O7 G3 I
}
1 {7 [; ~+ Y# T& r2 d, a $this->db->setModel($this->name);$ }) U p. y! N' E7 y; {' t
return $sql;
* M4 ?( c r+ m5 U, ] }5 e7 Y$ T! z) _
* O% T3 f2 s) R4 Q( P' `) Y/ B! v总结:
! ~/ E. r( S- u" b; u7 x5 l; m不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
+ f2 |& C& ~% s. Y P$ h2 C不建议直接用$_GET,$_POST
, w7 A! W' j. F. r x. J[/td][/tr]
2 s2 N0 M8 E6 I8 |1 K[/table]+1) d% h( Q7 P R; v- w$ x+ v, g
; U% D/ ~* X1 G6 P& V; n
. v8 i/ x: k. g6 H+ }8 L8 Z6 E |