下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
* J3 M; v, m* x4 m3 W( UThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件9 j3 V- @8 g% ?! h
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
* w% H5 t2 [/ G' V: V4 Q3 _% B$ W/ R使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
& L/ ?, M3 M/ H* H2 u* Q$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
) I% m3 m f2 F5 y" m8 P
; c' u1 a0 B) s( Z% ^1 e( O 或者8 |2 s' O4 O' s1 k. U! F) ^
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();/ B+ v F0 T7 k& e
2 L' l$ D2 ]1 b! Q. a$ f
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):- B. d' s" b- _, W
$model->query('select * from user where id=%d and status=%s',$id,$status);
/ J2 U) D' A8 c4 s7 K
8 W+ v1 n; g. w或者& _( L# p( {/ N" h" T
$model->query('select * from user where id=%d and status=%s',array($id,$status));' L/ N* x( E! }, N2 i' G
6 J- D2 E8 ?' l6 J: `! H 原因:6 J3 w0 B7 t5 h( Y
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
* ?! M3 d i; Q5 b7 ] z$ h* n原函数:
; b9 p0 q* j7 R+ S- |protected function parseSql($sql,$parse) {) b0 X% v6 \; L6 ^! \7 H% r
// 分析表达式
/ ~! a& Z/ r% y/ D' B if(true === $parse) {
" E/ i3 T$ H# l8 c $options = $this->_parseOptions();
. _+ w8 D# F7 W4 r! [ $sql = $this->db->parseSql($sql,$options);5 Y) ]& |5 m. u5 R: x- g
}elseif(is_array($parse)){ // SQL预处理" Y# W5 r( \* L0 C/ v; H6 B g4 \# n/ }
$sql = vsprintf($sql,$parse);4 h: L# ]: z6 A1 V
}else{$ u* \* H# O- V8 v. G* F! }" F+ `
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));9 x! n6 e7 h1 d
}2 t' i# a0 W' |9 z) J$ r" ~
$this->db->setModel($this->name);
% z- X: }* T1 R- l" s4 K. s( N return $sql;7 y7 l8 c2 {' h8 j4 M7 ?
}) F0 V4 U1 C" `5 u9 M& u) n U+ N
3 A) E W& r. w8 e验证漏洞(举例):. P5 R7 e: ^' g4 O9 r, f' _
请求地址:
' p6 l2 K- n3 B2 j. }- `http://localhost/Main?id=boo” or 1=”1, u4 a8 y5 p9 G! Q5 {) u* R; Y9 O
或
$ W- [8 r6 |, b* {/ x( ^: ^$ @% B! @/ xhttp://localhost/Main?id=boo%22%20or%201=%2216 t3 |- ^; l, k3 B; N r# ^
action代码:+ Z! X A8 m! n" X
$model=M('Peipeidui');1 K, I$ E2 ?7 J* b2 ~/ s* j+ @% l* j9 }
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
1 g+ m3 T; D$ M0 l% I1 o% D dump($m);exit;) f/ t! [9 _0 A( k' v8 }
或者9 H5 I$ S& n3 Y+ A
$model=M('Peipeidui'); Z' h/ Q" c) X7 r* a' h" }. p
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
# f/ M' O2 [1 z1 ^& U% O dump($m);exit;
& {8 w# i% F1 N结果:
. f6 R+ n! o& B" Z+ Z表peipeidui所有数据被列出,SQL注入语句起效.
( P+ T8 c5 z7 _& n9 d解决办法:
& x5 g# ^ z2 ^) t! h @! S将parseSql函数修改为:
$ H& Z6 |' H+ }) ~, M: |$ v# lprotected function parseSql($sql,$parse) {9 p9 ^. q0 O3 a% B6 e4 g
// 分析表达式" h+ z3 R; H. }
if(true === $parse) {
" v6 W) w# q0 Y! |/ ?) Z3 `( Y% a $options = $this->_parseOptions();3 ?: n e$ C7 x: Q" v4 E3 \; |
$sql = $this->db->parseSql($sql,$options);. r% ], Y# X* i! R% S
}elseif(is_array($parse)){ // SQL预处理0 |; r* J; X0 D4 ~
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
5 ?8 o9 N! H7 t! Y- Z3 l $sql = vsprintf($sql,$parse);5 X+ ?4 f5 @0 h: i4 s, m
}else{
1 S$ @$ o. n$ D5 k z& C $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
1 y9 L9 h b7 w4 }2 Q }; T7 W2 x2 E2 X& V. x1 N m
$this->db->setModel($this->name);% u* s" `- {* I
return $sql;
: r0 z& u0 ?# j/ p }
$ V) j% V; Q3 m$ Q j# g: u$ d* J) b
. ^4 s1 ~) ]8 ?8 W6 n8 G$ Z7 y总结:
8 o- {6 c' i0 W% |% p7 M不要过分依赖TP的底层SQL过滤,程序员要做好安全检查! \4 T5 ~: ], e* A, I) F! `
不建议直接用$_GET,$_POST6 \7 R5 O7 E. q3 c) c
[/td][/tr]* ~5 b" N) a7 i' `6 N7 P1 b9 ]
[/table]+1
' ^0 M- T4 u6 {3 d- o, Q7 r4 Q$ ^& z( J8 @7 `9 K. [
; V* e6 k$ i. v, e( c |