下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。9 S7 Z: X4 X& l/ r0 b+ y
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
2 `2 G7 n! m) G$ i" ^根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)! Z, [1 n: @/ j2 c
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
8 W& y3 J" y* @ P+ k0 c3 j$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
. n! y, h7 N) p" p; N$ T( L
. T) h6 C1 b1 @0 Z 或者
1 ]+ k4 G. b7 N, K$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();' K% r7 `7 v, Q( S
" D# C3 X& E n3 U9 [0 u9 \# E
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
$ x7 D) i6 {; D- n* j# U$model->query('select * from user where id=%d and status=%s',$id,$status);
! O4 m6 A5 O& w
0 u5 ^5 b; Y, k( Y" O或者
+ w. a% h( C9 N6 O9 h2 c# w( P$model->query('select * from user where id=%d and status=%s',array($id,$status));) T' ~+ [& i4 y3 n$ |6 i/ u$ h
- L5 i5 ^3 R3 `& ?: b0 ?& @
原因:1 w. A# Y8 ^& ?$ w
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.: _; s A5 }( q5 ]& p
原函数:
6 s" p( N7 [4 @ rprotected function parseSql($sql,$parse) {
; i# K# j8 v: x8 P( Y% u$ o W // 分析表达式( F0 g4 p6 G* o3 [+ u
if(true === $parse) {
# f; }" d0 d1 @3 L $options = $this->_parseOptions();: k7 u. T* ^8 _2 p2 g0 o2 ]+ l; O
$sql = $this->db->parseSql($sql,$options);
( j$ S# r4 u/ L; H }elseif(is_array($parse)){ // SQL预处理% @% n/ {# Q% z4 i6 U
$sql = vsprintf($sql,$parse);' o' B9 t0 k5 S7 m9 v0 q: M* k9 t
}else{
: c' e1 y. P$ b0 E4 m $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
% T! m6 a; I {; ` }
" l* W4 r5 f- Q $this->db->setModel($this->name);
( }- b% s& p$ ]+ r% Q7 W return $sql;2 |$ D* M, P2 m$ M) N3 t B
}
6 y5 x( q3 K5 w% |" a8 P/ D& n" k' i% s5 T5 S3 I5 a+ `/ l
验证漏洞(举例):
! V7 ^( I( O5 y0 p: a+ P请求地址:
$ U) e- d+ Z; n1 R/ ~: `http://localhost/Main?id=boo” or 1=”1
1 I) \/ @2 E# C, F6 C4 {6 Y: k, L或$ q+ B0 c. Z' V O& o$ B& x
http://localhost/Main?id=boo%22%20or%201=%221
- S8 [) A; m$ a9 z- J- x" W5 qaction代码:+ _# z, O' |& Z9 j/ C
$model=M('Peipeidui');
: o# j( U0 ~3 T7 l% I, B' r5 ?+ ~2 } $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
0 W; b! u" h- s4 n0 ]/ P) s* p dump($m);exit;
( d- T L0 |( P. h# E3 i或者
1 x7 R- e& p( C, A& M+ a$model=M('Peipeidui');. Y6 L* n# x; g! H V v3 E
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));, P9 F0 z9 x9 O6 z0 v5 b2 _2 A: P
dump($m);exit;
* v9 I6 \: r7 w" u结果:" C2 I% N0 Y2 u6 h1 f" |9 ^3 L- x
表peipeidui所有数据被列出,SQL注入语句起效.# ~! J. a5 y: r, c6 g* U* E1 u
解决办法:2 g$ m2 L f3 N6 ^$ Q: X9 j! d; \
将parseSql函数修改为:
' I. K& X2 F' Fprotected function parseSql($sql,$parse) {
9 ~! z- x# s8 _# t! `8 l+ ^ // 分析表达式
/ {4 [' O- a4 d6 h" B) R& U if(true === $parse) { H- u3 Z$ ]# I4 Z" x
$options = $this->_parseOptions();
% V* l5 o& ^- g7 k; Q) K% \ $sql = $this->db->parseSql($sql,$options);! i) R+ E/ n& A4 `3 z9 K! d
}elseif(is_array($parse)){ // SQL预处理
1 ?* Z5 Y: |7 u9 i0 ? $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
6 { P0 K$ v, L $sql = vsprintf($sql,$parse);4 y0 z2 L) S* d
}else{% |3 l' y7 p) z7 ]/ c$ \2 n: U) a
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
0 T' j/ v# E& j1 V5 I }! N' o$ u& C& U3 g
$this->db->setModel($this->name);
, `; q0 T. N3 S# v return $sql;
& ?$ M ?2 g6 i* i8 Q2 T2 A }
/ e6 O7 g i) @+ z! `$ E! s. m& P0 J9 v! A, {6 K+ j+ k8 n i
总结:
* d3 l" g7 K5 u, V/ t不要过分依赖TP的底层SQL过滤,程序员要做好安全检查+ q' j/ g* S8 }; c# ^; e4 Q
不建议直接用$_GET,$_POST+ r2 X* X5 ?6 E# E/ ]; z
[/td][/tr]
$ o8 Y" H) `- W; b$ A" a+ ]+ E[/table]+1
. _6 n) r( _- |- @1 K
2 y+ m, o# I0 X8 ?2 P" m
8 M4 ]' M! H8 ~0 V/ \ |