下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。% D( ]$ w t" P C& E N* ?
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
$ U) H6 {- o1 j根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)" \, G( P6 ]" B& F9 D
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
8 ~6 M5 ?) {$ K" z6 i1 ~" L+ H$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();3 ]1 t) w) [+ c5 l$ Z
d0 _6 B& |% h( C u( s
或者
$ q. e; [# d4 K- f+ X$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
( T5 B( a" W: Z* M
# E( e/ R; r% J; Y$ q+ ~ 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):' u: w8 A3 m$ C( j
$model->query('select * from user where id=%d and status=%s',$id,$status);' X+ `" S7 I/ [+ o4 [
7 Q+ e+ G9 H4 i4 A5 L5 `% o
或者
) R; @/ ?9 B" d# `3 d; m$model->query('select * from user where id=%d and status=%s',array($id,$status));
+ W7 Q! l5 I/ f0 y& Z" F
3 s6 F8 M, `& _5 c! U; D) l 原因:
4 N4 ~) u1 M7 J& i% m: jThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
3 h( p E$ j- F+ o" ~5 {原函数:
$ S9 Z C0 q* T7 Y B3 mprotected function parseSql($sql,$parse) {* b( ^( Q' B+ S" k9 Q e3 F: K
// 分析表达式
" h4 e. N% |% m4 z/ d' q if(true === $parse) {
! K! N( m' P8 ~5 ~ $options = $this->_parseOptions();1 }- Z! v$ c, s1 ^
$sql = $this->db->parseSql($sql,$options);3 z9 Z8 I; k( E0 L5 k' E5 `. Z1 n
}elseif(is_array($parse)){ // SQL预处理
- `8 I, C& L+ F $sql = vsprintf($sql,$parse);
; O$ j/ \& R+ L; d2 ~; q; J* c3 ^ }else{' Y# T/ v' y' ?5 `& l3 u- h( k
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
: x% U4 x2 Z" F9 _1 l }
7 S a1 L/ Y8 O* T5 d! B" H0 K/ S $this->db->setModel($this->name);& _% `1 _6 m( b* L! H2 b2 H
return $sql;$ K; y' T$ f- R% d# W1 y% y
}
+ h3 M9 {- ^, p$ _4 J5 v
5 |4 v: m I8 l0 W p, I, D验证漏洞(举例):/ N+ x0 K' \ s
请求地址:
5 i3 z& j7 F- b, A( U: @http://localhost/Main?id=boo” or 1=”1
' N) p W1 F ~7 x/ n或8 v; ?" a" o* K$ x e" J
http://localhost/Main?id=boo%22%20or%201=%221
: @/ D0 C; `7 A0 w% aaction代码:
1 Z" S. d+ I+ |& A$model=M('Peipeidui');
- t; h& f7 e) Y0 g6 }0 w $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);8 w! l) ]; Q9 U* u% s, h h! }; d
dump($m);exit;
0 @3 e9 B$ Q# [1 e或者& @% `/ J% N7 g6 O7 m
$model=M('Peipeidui');
% k) p( K) h0 H: |7 m5 j( X $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));. h& o; }1 l h9 _8 b
dump($m);exit;
. @4 }, J) C' Z* [7 K: K8 D结果:
9 I! Z1 n2 T- G表peipeidui所有数据被列出,SQL注入语句起效.
1 a2 u$ K' x1 v) S$ b4 S解决办法:
( {; p/ J9 Y2 ^! J6 H+ l将parseSql函数修改为:
1 F- {1 }9 l9 ?: ]- dprotected function parseSql($sql,$parse) {
3 \' w! |. M* l6 b$ v% d/ b // 分析表达式9 W2 o6 P0 v3 J0 ]5 a# F
if(true === $parse) {
7 z: G4 H/ D& P4 i4 p8 m4 }: h: N $options = $this->_parseOptions();
- ~5 j- Q: U# n+ G0 r $sql = $this->db->parseSql($sql,$options);
2 E+ B5 s: [7 Y4 t' Q5 S }elseif(is_array($parse)){ // SQL预处理- Z2 w2 u n1 ~! I, Z$ G
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码8 I0 c5 L$ S+ u
$sql = vsprintf($sql,$parse);% Q" k8 Q6 Y i: x3 i+ o! [
}else{
8 W; I: u0 ]& d c! z, t $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX'))); G! i2 R* y- s
}
3 [' u& c Z9 b. V* J) k$ v- a $this->db->setModel($this->name);! t; r5 Z6 U; Y1 ] j) n
return $sql; u; a% P1 |$ R& L, j3 m
}6 @8 k$ S9 z6 O0 r8 x; E1 D/ H/ k# O, p
% k. L0 R7 x( R总结:
2 }8 i3 ~0 F7 i/ N4 {: D# u5 D7 I不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
3 w9 ~ v0 f. K不建议直接用$_GET,$_POST1 K. Z# N4 k% L' ]' y: {
[/td][/tr]
& t: _) C0 _- ?/ g3 N( w8 l) ]& H[/table]+1$ _$ v2 F$ Y' q: E2 o9 i
9 g' _: U) U0 z% f. u! _- V
" z/ A! {( s6 u* q! I, B$ }, f |