下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。$ `* T2 F. v8 Y4 @4 o) k( C! U
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
7 T4 x% ^# L& Z. @) {- y根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
3 P. l( U4 L' K3 d0 f0 ]- V+ A使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
8 d2 F$ L' i3 X3 ^& b$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
' }6 r. G( A+ X0 B6 U& L/ {# P4 o5 H! M3 X" d! x3 T0 x
或者! [ }) y5 j& K2 U
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();7 K, z6 x% m0 l
, @+ M* \; P! W# v; O, `7 s 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
2 G( B6 K& ]9 p# d: J6 b$model->query('select * from user where id=%d and status=%s',$id,$status);+ E0 V/ Y! K) z7 u
* }3 f8 ? S* h& o或者! l c1 h) [2 V! u K& M
$model->query('select * from user where id=%d and status=%s',array($id,$status));
- R/ B' s [) L" d( K$ W3 Y" `; ]' l
4 @+ T) M* a. M) W5 t8 z+ b2 M2 M 原因:
' ?" T( e0 V; ]0 V) {ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.5 a, k" P& L4 S3 j% n9 D& `
原函数:
% \2 I( d9 h5 W5 T7 \' ?protected function parseSql($sql,$parse) {6 [7 T, ]6 w6 h% o" O2 ^! V! ?
// 分析表达式6 N- q5 O$ m& K+ [' }' b) Y/ o
if(true === $parse) {' O: I: V( Y/ S F" t0 N- N& V
$options = $this->_parseOptions();7 l' i2 U, ^: ~+ x& v8 A+ O9 }
$sql = $this->db->parseSql($sql,$options);
( R6 ~% `0 |8 r3 N/ J* d( k }elseif(is_array($parse)){ // SQL预处理
( a, L+ a0 `# f $sql = vsprintf($sql,$parse); Z' m( S- i2 A, [ U9 R& ]( W6 o$ ]
}else{
+ u" l4 V( [4 ]- m! B; A $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
- a+ M3 E0 O/ z, [0 I% M* ~ J3 h0 i }
K( U# G: {6 j: j% U! c( D( q $this->db->setModel($this->name);
/ P% ^8 [# W1 c l" U7 W% f+ E4 N return $sql;
1 N$ j0 n3 ^* F' N; l }
' h: A% q! X. D4 G9 b2 j \( E: R
, @ H; b! |* m! x- V- V5 g验证漏洞(举例):
2 K; l7 e) F. ~# O$ [请求地址:/ }- i, Q b R" `7 K
http://localhost/Main?id=boo” or 1=”1
+ p0 P1 Z p- \, B, M( @或- s. l% V* D: }
http://localhost/Main?id=boo%22%20or%201=%221$ i* B6 p* Y( M1 ?; p2 L9 s8 V
action代码:
t! r7 U0 j; p: B0 ^. w$model=M('Peipeidui');5 P. i4 u5 C$ R" I' U
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);! p8 c0 Z5 l) t$ J4 t0 T' \
dump($m);exit;
6 x: r4 \; v% k: p( ^! U% l或者
* O- r+ F* b5 u' R7 ^$model=M('Peipeidui');; Z$ j; P X% r9 U/ p1 I* W
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));: R8 I: }6 H. p5 H: r( d
dump($m);exit;" v& D6 }9 D- _/ }$ E# u. r
结果:
4 B5 ~2 _3 H, }' {7 O) T9 q表peipeidui所有数据被列出,SQL注入语句起效.0 B# B6 Q( M# C2 y1 _6 S/ S2 u: @
解决办法:7 `# ^& b L; J& z- E* g
将parseSql函数修改为:
; f+ L- _: T2 q( N% eprotected function parseSql($sql,$parse) {
, p, P4 W( R: P' u! O1 B // 分析表达式
% P; X; D1 d$ [9 J! O/ ^ if(true === $parse) {
- r' u- E7 l/ U4 C: D6 R$ f $options = $this->_parseOptions();
3 e3 A& m# `' H4 E; u6 w* J $sql = $this->db->parseSql($sql,$options);- H& O& R9 X9 l9 h6 ?7 e3 S
}elseif(is_array($parse)){ // SQL预处理 ^$ ]0 h6 B* a! k: H) _
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码" Y: ^9 Z# T$ _( o; c8 \: I$ e/ C6 D
$sql = vsprintf($sql,$parse);
" O$ a; |/ v: }' T( Q4 D }else{7 }3 T ^6 D2 j' ?; w6 ], @ T
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));3 ~9 g! \: G$ y0 W% S
}
8 x4 t( q0 l% D* i4 ] $this->db->setModel($this->name);
; Y. a$ e* ~+ ?: Z return $sql;
) P7 m+ s/ P+ K+ m! v1 s }
% w- I" M& v5 V9 o" m* j5 ?$ h( f! b/ q% b# d0 @8 o; E
总结:5 ?- w! [" v# O1 u
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
$ Y" o6 M$ b7 ~3 e9 c5 u不建议直接用$_GET,$_POST! g I; h8 c" W5 k8 S
[/td][/tr]6 y5 L$ i. q0 w& {& d5 v6 b
[/table]+1+ x7 |' A0 n% g) M+ p' o5 c
$ k3 m5 W! x: G
6 q$ z7 O8 b0 @6 e |