下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
" ]8 L/ M; X$ l x5 {8 aThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
7 e$ g+ p5 r3 }6 `$ W; D根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
9 ]0 @+ b) U5 F! F9 t使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
5 v5 w- E# M+ _+ c$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
5 f* d: V- Z' p- z- t) S* s N9 F! s o) i9 q. d# i3 Z
或者, z L3 e8 g( h. H2 P
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();7 F) K& C' E8 f: Z( i$ N3 ~
, O& |/ k) J0 t
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
/ R. f0 B! w* a$model->query('select * from user where id=%d and status=%s',$id,$status);
3 x% b- g! ~6 C1 m( \% v& v
+ ^0 \5 f: }- D' k或者
$ d2 I% d* q# G" N, G$model->query('select * from user where id=%d and status=%s',array($id,$status));, E/ H- G5 t5 V8 ]2 S& q6 s0 s+ E
* @, e- W8 t! S2 i4 P6 c 原因:+ S; ?5 M' |. t2 _) R
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.8 W3 N& E8 F/ w) S1 V8 h/ W
原函数:
, m3 w) D- r+ p9 h b+ h% \ Fprotected function parseSql($sql,$parse) {
2 C9 b2 {: C( s, M // 分析表达式# W" \8 @$ I# N4 V* ?0 S" K
if(true === $parse) {
% n+ W6 V9 z- s) o3 y' W( Z# W' { $options = $this->_parseOptions();4 J# g# k( j* ~' {/ |/ Y* t
$sql = $this->db->parseSql($sql,$options);
9 ]( ~* E! [( D7 H }elseif(is_array($parse)){ // SQL预处理
( i& A& H) t% }; T4 n' `' h $sql = vsprintf($sql,$parse);" J& C2 f- y1 V9 R$ |
}else{0 ?* {2 A# x y' z1 f |* t$ ]7 ~! F
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));( ]) [- s8 [) v) O3 t/ d
}( Z" P4 }2 E& m
$this->db->setModel($this->name);( y) t, Z# A0 F8 \4 p/ ?
return $sql;4 r6 n5 }4 F L( |: c" l. c' F
}
8 A8 v! E3 p3 C; x3 E0 s
5 q# `4 q2 O8 Z8 N0 y, x' ^% @验证漏洞(举例):& x% Y! [5 f7 k) {
请求地址:- t) `8 b) w8 V) m5 Y$ }6 h
http://localhost/Main?id=boo” or 1=”1
& b1 C; V$ ?9 s或# \ G5 E: s9 h8 A
http://localhost/Main?id=boo%22%20or%201=%221
( A% s8 F+ t( w) Kaction代码:* ~& M O+ d0 _' i) Y. Y
$model=M('Peipeidui');
! f: t1 E0 h9 l, n4 a $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
+ B' I# C' I( W6 P& w$ H dump($m);exit;
8 c5 W1 h+ j5 }/ y! T或者
" U4 J& ~( p( g0 Q4 j$model=M('Peipeidui');
1 w/ o. h: I1 b( p+ o+ F% F7 C" ?5 D $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));, d0 N3 @: N" ^" w: P
dump($m);exit;" c4 K% X- u5 N; \
结果:9 K8 c; P' Q: r, w- l ]
表peipeidui所有数据被列出,SQL注入语句起效.
7 \5 C8 [& O* [5 e解决办法:
4 y x8 J- ^# I% e将parseSql函数修改为:3 l0 Z' x' C& ?/ {4 |
protected function parseSql($sql,$parse) {
5 Z( b5 l+ [: @1 E4 U6 ~# z3 r // 分析表达式+ ~( D7 P3 a% m) K+ l, i
if(true === $parse) {
# ] _) K4 R' J7 r0 G$ b) } $options = $this->_parseOptions();( X t4 }) m. A' X
$sql = $this->db->parseSql($sql,$options);. R7 t( u9 d+ {8 o6 K* m u
}elseif(is_array($parse)){ // SQL预处理6 w( g5 o+ ~0 Q( \7 X# L; z
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码6 }0 Q n2 ?# a2 R
$sql = vsprintf($sql,$parse);" `3 x q% }8 \3 c3 G( n' r
}else{
5 [' f* k( ]1 P9 p `. Y1 H $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));, n# |4 z) Y/ `( X' V& m3 e6 P
}
# X: A: c' V( _, j $this->db->setModel($this->name);/ K Y: z5 U2 M% ~0 P4 k" F
return $sql;
# l1 Q! i; k/ y( N0 u }
5 a$ X ^: |9 P8 T* ]9 }# D" ]
H9 S8 d; E& q+ m) [7 U总结:
% C2 a t/ D, Y2 e1 q5 {不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
! I6 u) H+ J+ H- ~- ~0 ?+ o不建议直接用$_GET,$_POST
" @% S; D- B( z7 e+ [[/td][/tr]
' E" ~+ \% ^7 k2 a8 L/ E[/table]+1
- S; G, i9 {& D
- J. g0 C- ?9 m" J
) x( P& I+ L* c7 r/ f |