下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
" h+ {1 h5 @! e- c+ rThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
) L" F' O9 o8 g1 N5 N6 B7 I, E根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
! _; F. n6 q* @5 |6 x5 w/ K使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
! g/ r+ Z' [* g$ Z9 {$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
% _0 S8 _4 Z* o
, o9 U U! N) m1 [3 F 或者, h+ S, Q! _3 p! l8 e2 J- K6 z
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
0 g" h4 q1 O. T6 Z. c2 {/ {; b9 A i% z
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
0 t! ]! u: o$ q; n- m& C a$model->query('select * from user where id=%d and status=%s',$id,$status);
" R3 c3 l- a3 X, ?& f& I& [
+ ~: m6 f7 \9 w8 h或者
) O' B. ]3 x) l$ e+ \$model->query('select * from user where id=%d and status=%s',array($id,$status));
: l3 S! ]0 a: ` x; x
' {) X0 y& _3 G8 m Q8 H; m 原因:2 B% v* S: o6 A, a3 H7 E
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
9 j* V0 I3 x- B3 Y+ a+ V4 w原函数:: V( t+ a1 E Q+ Y0 o* S( l" j
protected function parseSql($sql,$parse) {
1 a6 K: o( b7 M" @! O4 O3 \ // 分析表达式9 q% T. \0 @) A; R
if(true === $parse) {5 e% r. E# u6 B' `( O
$options = $this->_parseOptions();$ l1 Y- n0 L8 c$ T& e, G( R6 g
$sql = $this->db->parseSql($sql,$options);, {! u* T1 F9 V! N% S2 e1 m1 B) l/ W
}elseif(is_array($parse)){ // SQL预处理
' r; \* {# H0 w- Z+ N1 _; x2 m $sql = vsprintf($sql,$parse);
& |& ~& i# {1 J. _ I* ^- z+ U) k }else{
) C" w/ z& k H0 [& V1 ]* }: J $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
) F+ a6 }. Y6 q6 o u }5 L) R! \5 v0 c/ K+ V
$this->db->setModel($this->name);% L& l5 z; }1 [
return $sql;
- {9 z4 y1 O7 T+ O& C+ W: j }
c+ r, a" ?* a6 N" P+ D6 o( L! }" Y- [# V) d
验证漏洞(举例):
5 p& _ J! @& m \7 Q请求地址:
1 n V: c6 Y# d0 [. _ M; q# Thttp://localhost/Main?id=boo” or 1=”1
9 r! ^3 M2 N) k# U' o3 E y或& @7 h) @# \1 S& [
http://localhost/Main?id=boo%22%20or%201=%2211 b2 ~* ^2 N, H9 w9 V$ T
action代码:' b4 P: D" W0 X2 J; P; i+ I
$model=M('Peipeidui');
$ k' p+ T0 O0 j $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);# ]2 f% ?( C3 p Y. [
dump($m);exit;
/ t: O- N3 E) k6 \! z5 U6 q或者
5 k# K+ l V4 j. ?1 o, B% x7 |$model=M('Peipeidui');" b0 y. O( X" S( L! ?1 r% C6 c- U
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
2 K% W3 z& [6 j4 z$ j dump($m);exit;$ T! N5 Y$ y. O; v6 j
结果:
& d" v+ C+ f6 N! D9 q; ]! C o表peipeidui所有数据被列出,SQL注入语句起效.8 u% F3 m% L! i3 U8 V
解决办法:
" e$ A5 i* j7 z; k0 D将parseSql函数修改为:# L9 f$ R7 i+ Z" Y0 @4 l" ?
protected function parseSql($sql,$parse) {) `! o7 e4 P+ J5 |) P
// 分析表达式
* a+ S- }4 S6 Q) L) u: o if(true === $parse) {
- M r2 r3 s- K1 c3 X; P6 x) H $options = $this->_parseOptions();
/ i( W O$ V* z4 y- w v3 X $sql = $this->db->parseSql($sql,$options);
# j# S9 R6 S/ x }elseif(is_array($parse)){ // SQL预处理
, ] j5 d2 e" v5 V6 c6 o$ U8 Q $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
2 Q. r+ F' l. ]( l0 i $sql = vsprintf($sql,$parse);
, N7 h) [' U, {+ z }else{* Q3 b+ U/ D W3 a
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));; K2 Y! i4 H- a/ R' p' H9 t+ G
}
) T# v) T7 x4 b( s5 s! B( [6 O $this->db->setModel($this->name);; }" F7 g. Y/ K9 T+ [
return $sql;
: E- g8 t2 [) Z' U" J }- ~; t. N [! \+ Q. T
7 W8 A3 P7 W' Z% w$ \1 _5 R9 `
总结:
, t9 R; J3 C# w4 v/ K不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
# {; ? p! |- f7 K' b7 W不建议直接用$_GET,$_POST
, _2 [8 G ~* u9 V% r[/td][/tr]
: y- R7 w8 l, D9 u3 q- d8 t( v[/table]+1
( h: r: n; ?; a
/ M q8 |$ u9 Y6 x; j) A: B, L( I+ g7 h
|