下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。6 o9 ^, @* t7 y4 g: u+ ]
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件; d' V6 Z$ @" Z* E% o8 w p
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)6 F- ^0 r% V' ]5 E& f( Z1 Q
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
! k& K! L+ v# u. L, h* x$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();# @' m7 K9 n, i' t
* l8 Y+ j- Z8 J. n: d 或者
5 B! u& F9 F' W% B* C* u4 z" U$ b$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();; O: d. f7 C Q, ~
' x6 }$ Y6 G' \9 w1 e' T; Q
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
& u% g! w/ t) D ~/ f o ?& {$model->query('select * from user where id=%d and status=%s',$id,$status);
+ U) X: E. U' u: \" \ q" T7 D" }/ N- A- w0 A+ q
或者9 i6 ^$ ?3 H4 B7 V2 {) [! [/ h
$model->query('select * from user where id=%d and status=%s',array($id,$status));
( G% H( @. K$ D& b' |: ~! W; g
7 V; K6 H, X5 U& Y' S( r3 _ 原因:8 g7 n" R( g; R! P3 T9 q
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.3 a2 J. V) R; [
原函数:
% h7 F" Z2 @2 N5 r- c3 `protected function parseSql($sql,$parse) {$ g; U# r0 t# v: H9 x4 {
// 分析表达式4 t+ y8 U* Z) s* s5 |
if(true === $parse) {' y* T5 Z( U# a
$options = $this->_parseOptions();
# Z. b! ^) W# Y% m% h* f $sql = $this->db->parseSql($sql,$options);8 G }6 q. K4 u5 r( O. U8 F
}elseif(is_array($parse)){ // SQL预处理
4 P! i N- l7 v+ l5 y' L' Z $sql = vsprintf($sql,$parse);- V, p( Z" R1 w: P' F3 H; _% T
}else{
( w5 b$ f( D7 D6 R. G, `8 b $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));5 U5 W$ J# n9 ?2 ~9 q
}
8 F, m. e# h9 i x1 K* H/ u( J $this->db->setModel($this->name);
' _# R" S' m$ F& K! X7 {& q return $sql;+ i* E1 n* F( f/ Q7 a
}
7 Q+ k% k3 f' R+ ?; i
' e0 i# e0 s8 h验证漏洞(举例):7 l- v8 n7 w1 [7 ~! F
请求地址:
. N$ t7 |& B7 ~* Z5 e0 uhttp://localhost/Main?id=boo” or 1=”1" A! {. q0 m4 Q$ T) [ @8 C
或
: t# f+ t% g6 ?9 ^$ h0 dhttp://localhost/Main?id=boo%22%20or%201=%221
# m, J4 C' [' }3 ?3 k5 _action代码:9 S5 \; b# i2 [2 \# q% y
$model=M('Peipeidui');
4 ?4 k4 _1 a) `* V$ G $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);4 Y- x% [ \( t
dump($m);exit;
( k& I% \. j3 n3 t或者) c, y& n& c3 |2 h0 X& e* I$ f
$model=M('Peipeidui');8 w/ W5 a, b8 N- b/ c
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
3 V# ~- u& B$ k' b dump($m);exit;
8 e( P, x" O7 P9 l. ^9 [. s0 k结果:. f7 Y+ {! f; r6 b4 a
表peipeidui所有数据被列出,SQL注入语句起效.
4 ~: {! N/ J2 `6 K解决办法:2 w( h9 R4 V7 `; }
将parseSql函数修改为:
3 A+ r' |% U7 L. _# f7 v/ Jprotected function parseSql($sql,$parse) {9 V! n& o7 d: P+ r9 T d& e
// 分析表达式
5 G# v" V! c8 M Q! w8 Y6 c- u" X" | if(true === $parse) {9 C" x8 X. v, q! t3 J4 I
$options = $this->_parseOptions();
" T9 [1 E% n; [( K, N- d $sql = $this->db->parseSql($sql,$options);
5 d1 q& Z& S+ `+ F }elseif(is_array($parse)){ // SQL预处理( n* p6 ^* j1 b; O" a' x
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码% |" F# q& L) X F ?
$sql = vsprintf($sql,$parse);
- }. V. e/ |9 j- S( t" a }else{
$ @2 |0 {3 E n2 J( A, l) F. L $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));: _/ v1 `0 T' p" E% K M% t* {; c
}
( M5 _6 |4 \7 t+ ^. B $this->db->setModel($this->name);, h q/ Q3 a% O, u+ ^# \; n
return $sql;
0 }0 b0 L/ _& Z5 v; Z }
t5 f# t8 x# V& J. c7 c
5 c, Q* J1 U* e" V( Z; R0 H总结:
3 w, ?0 j9 }* }2 j5 d9 m- A8 ^8 d不要过分依赖TP的底层SQL过滤,程序员要做好安全检查8 ?$ o9 D5 {: q* h
不建议直接用$_GET,$_POST4 m2 M: c, R2 o$ G o
[/td][/tr]
- ~5 A7 Y% S0 _: B[/table]+1
1 A% |" g$ y( [; R) a) ~4 f8 M# c! D' |# v
% B2 h0 V9 @; R6 J. }% G# {
|