下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。! y' {# m) H+ C7 A# i/ O
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
3 k0 V# u5 d" z根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)* t" y5 j: ~/ u- X6 x
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
7 a$ C0 ?" s) l- m1 q! w0 N; x$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();( ^' C- P% s7 S# C' S) r. X d4 ?
: o7 y+ i x' ~
或者
5 \% a6 H2 q$ j$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();3 b4 C5 I; M; f3 j
+ h; R* \5 w8 i. v5 c 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):3 @- {$ x2 F& |; _. T. l
$model->query('select * from user where id=%d and status=%s',$id,$status);" o/ V; }4 n F
; h+ ^- t) w2 \4 @' o% u% L1 A; K5 |或者# y e u s( }/ s4 V
$model->query('select * from user where id=%d and status=%s',array($id,$status));+ O3 I% m M9 {6 z0 G% Q; Q
' n2 [, k) Z: X! G: r" _) v0 E 原因:2 ^9 g0 B q* f/ u
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.% ]! @0 l( J2 x# y1 B- F
原函数:
! a4 e" ]" A; h: r$ g/ xprotected function parseSql($sql,$parse) {; j- B9 A! f+ R8 D8 z
// 分析表达式3 R3 \& D( w9 U! k- a
if(true === $parse) {& j4 j9 q8 L* {
$options = $this->_parseOptions();; z( C0 @& D) R# @2 g: q
$sql = $this->db->parseSql($sql,$options);. Z0 Y& w; _6 [/ s, I b: K6 V
}elseif(is_array($parse)){ // SQL预处理" \; X" U3 O# x
$sql = vsprintf($sql,$parse);
. a* J$ [) m6 E) l8 D- W( p, ?5 F% s }else{3 S4 D6 H% H0 p4 i& _( f, t
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));! z3 P% A0 O/ l
}
. U& W/ [. r5 A1 a" S" L1 ^ $this->db->setModel($this->name);( H, D$ |. H- Y& o( n5 q6 Z% G* B
return $sql;. Q0 Z% ]* o- d7 |% F5 m0 C
}% b+ {2 c& u/ ], W
: `) q3 z0 I- M) N& J5 s' D验证漏洞(举例):1 s( ]5 f4 y$ S6 a# A' |0 Q
请求地址:6 |3 o- Q+ ~' p3 Q( Q* o2 t8 Q0 Y
http://localhost/Main?id=boo” or 1=”1) ?0 B' f1 @& i& I* l6 f2 L
或, P6 h4 |' U0 G; p2 [. x: }& @
http://localhost/Main?id=boo%22%20or%201=%221
* e& o y9 @- H+ taction代码:
; \+ |' s+ U, ?, n$model=M('Peipeidui');0 d8 ~) _1 _- I7 }
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);- b1 B/ S3 F# e# ^; G- d
dump($m);exit;
* g9 I$ s( q: y0 G, L. g8 z或者" Z% Q: q4 N5 e2 M, H0 L
$model=M('Peipeidui');
: g+ D, Z/ s6 S/ c+ d $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
# _4 Y& d- }4 T dump($m);exit;$ Z' j, e' @4 d: S
结果:
1 T+ X/ t9 I4 w0 C% z( D表peipeidui所有数据被列出,SQL注入语句起效.
. x4 [8 F# m" ^; i S解决办法:
4 ^' j$ [1 u4 k$ i- E( x将parseSql函数修改为:" n w7 i- r I% k
protected function parseSql($sql,$parse) {
! B; K) d0 x& o // 分析表达式 W5 w% S' o# x2 |# L5 z
if(true === $parse) {
+ i$ q: Q, J5 w2 \5 t+ T0 m $options = $this->_parseOptions();
' h A5 O6 T3 ? $sql = $this->db->parseSql($sql,$options);7 z% T" ~% J# S6 {
}elseif(is_array($parse)){ // SQL预处理
2 R* g) g# u i* ^8 I1 s* Y0 N $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
4 j- D6 ~- g) { Q' t M/ Z( X $sql = vsprintf($sql,$parse);# x9 D" ]9 k" ^# E% K
}else{
& u5 _8 D5 a' w( s $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));) G1 }7 p' B* y
}1 \' f% c! r% g; _9 W
$this->db->setModel($this->name);
- U6 ] B, g _0 r7 y return $sql;7 U t& k0 V4 q6 k; ]
}5 j I% G0 B- s- W" y
+ R2 i! d1 F9 I/ m$ \8 K总结:3 Z8 p { F7 ^+ [
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
! R& N7 j T5 f7 J T不建议直接用$_GET,$_POST( M5 F) P5 q! k: Z" ]
[/td][/tr]
8 ?! I( h- R7 `8 Z1 f$ L! Q3 ][/table]+1
9 E6 d/ O: j7 J0 o# W+ w. N! N
6 u b& A0 V. N* [3 I r1 R j9 J' L! m( ?$ z
|