下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。# W6 }) K9 P! R
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
2 i5 K; L9 \" j$ {根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)9 Y5 H: e' |! E) m( f
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:( ~: ]" U6 w! Q
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();/ J' P! t; y7 [
7 d% z9 n' u: X: I+ `, ^" D
或者$ I* L4 d/ ?! X" k
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();! T, K. Z9 U6 x) ^
2 U$ F. ?) K. d4 o 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
2 C f6 m& v; u" _* j& _3 z$model->query('select * from user where id=%d and status=%s',$id,$status);
4 S+ W5 z( y4 [; J! J5 r! V# X0 I- G2 z3 A7 K K7 G0 W
或者5 c) B1 ^4 C! w( J/ o
$model->query('select * from user where id=%d and status=%s',array($id,$status));
! U& [& \1 {! b% }; }
5 ?0 n' U& O5 b$ C) {/ _ 原因:: s, [4 C4 a" I
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
" @" D: w/ t g6 B* l, E原函数:
# h* d" }0 C: xprotected function parseSql($sql,$parse) {
* I: _1 X4 V: {% B // 分析表达式
. j: Y! h8 C: X# x1 [% [; l" b if(true === $parse) {( b) U0 u1 l4 ]4 @4 c3 {& N$ I" x
$options = $this->_parseOptions();
8 k9 l. @4 ]" A i$ l $sql = $this->db->parseSql($sql,$options);
, P2 B1 O% Y9 X- @# e! ] }elseif(is_array($parse)){ // SQL预处理. Y+ _- \) X5 m" A/ S& f+ J
$sql = vsprintf($sql,$parse);
! P/ G; ]3 D) s, @: c2 m }else{: Z5 N& T1 I3 a, Q: F5 j+ T
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));* `% T9 R/ o, K( J, h1 t. ~: P" \4 p
}0 s/ `1 m/ q }1 v! ?" E) T# p
$this->db->setModel($this->name);2 U/ |- y& s" V; d
return $sql;9 W( N/ D6 x9 u- c. X* U* P1 S
}
1 G& b7 w; K# l8 x$ o8 q1 ?1 E9 g7 n# \. O! |
验证漏洞(举例):! L! d& T) \; s
请求地址:
) M+ T" q- S7 K+ a; |6 k7 U3 T6 `8 thttp://localhost/Main?id=boo” or 1=”1
7 H, N. I6 b, e! t- D1 S& [或
( @) W. L' z3 X" ?http://localhost/Main?id=boo%22%20or%201=%221- V! l/ l# k. S
action代码:
# }8 L8 }; k4 N/ L! Y, t j$model=M('Peipeidui');; o+ R8 [" Y0 o5 M/ ~" K
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);# ~, J- [3 v: X+ J- |
dump($m);exit;( ^% O% g# K+ X5 M2 F. v
或者- w$ G8 j0 j1 \; A
$model=M('Peipeidui');) I) J( L \0 H& v
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
* {3 A8 t r8 |3 B dump($m);exit;
/ ]$ o* ]; G/ i$ v结果:8 V$ q% t. l, V
表peipeidui所有数据被列出,SQL注入语句起效.: i' Q" I9 z4 H: t' H" K
解决办法:. c5 _+ c: b- ?% `' Q) S: B
将parseSql函数修改为:
: J0 z V3 ?% i3 @protected function parseSql($sql,$parse) {: `, H# V% d( ] ^. p
// 分析表达式, I( E9 o$ Q b$ l: m8 w
if(true === $parse) {
! {# f0 @6 }; o $options = $this->_parseOptions();! h9 i- F M4 I8 k9 o6 {
$sql = $this->db->parseSql($sql,$options);
3 V* }7 p9 ~" B. M6 t( ]& k. ` }elseif(is_array($parse)){ // SQL预处理) V. y$ m6 j. f9 b
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
7 x) K6 V' O; J! _! v $sql = vsprintf($sql,$parse);
2 u: n8 j* ~( X* P5 K }else{8 X5 L6 U5 f o
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));0 u( @9 X7 J# X' K4 G( D" V
}& G; b! E! u5 q! T
$this->db->setModel($this->name);; ^- b/ @7 \# c; k
return $sql;
( \' n9 W& U M3 n+ V2 e' U% n* B. _% M }
3 I8 t! f: }+ B3 d
1 E, C0 \! ?, j, p8 q: m. V总结:
5 f/ W: r8 M3 Q ^/ x. J. C不要过分依赖TP的底层SQL过滤,程序员要做好安全检查: h8 I+ s. _& d) i' C; {4 q: t4 X4 c3 u
不建议直接用$_GET,$_POST
( H9 V) a5 U: Z. R$ W' r$ Z[/td][/tr]7 A+ U9 C- E) X5 [* e
[/table]+1
6 M, ]5 ?' |* o) l. y0 N3 [+ H! V. X3 ?. H8 K; \
8 M5 c g7 J2 C& `1 K |