下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。# Z B2 ]6 y; p
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
2 y, }0 K+ j, T+ Q根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)* D8 {+ Q% T' M0 N
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:! d/ k" r/ a* Y; F3 _
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();% F A6 w0 |: _2 u4 S( C+ ]
1 W8 a" J/ i+ Q7 ~7 E- U
或者
G" A# _: w: O5 o9 o2 a0 r$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
; q7 j3 ^( q# w, |
$ t7 w5 c9 M3 C 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
& R. @3 M+ [5 ~/ f9 [$model->query('select * from user where id=%d and status=%s',$id,$status);
! ?' ?" b: L3 o- @: G1 A/ g& g" l1 e8 T( q# [6 P2 S+ M+ |* ^3 a
或者) N$ u& v A& n1 b& g- m
$model->query('select * from user where id=%d and status=%s',array($id,$status));
0 Q; z% ^* p0 m* O; }. H. w r2 Q; O( A5 ?
原因: }9 q6 o4 L; a; S6 g
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
9 i M. k5 U7 P原函数:% |7 f) x- D. r& _
protected function parseSql($sql,$parse) {
2 s- R; Q G& X8 m4 S // 分析表达式% x( h) N6 w- y; E3 S
if(true === $parse) {
; s+ D1 x ?" Y $options = $this->_parseOptions();
. v% z! m; i, @ $sql = $this->db->parseSql($sql,$options); s* g+ B* {& }! ~ C
}elseif(is_array($parse)){ // SQL预处理
; a8 {+ A# e. R7 N8 J $sql = vsprintf($sql,$parse);
# u4 d* \0 U8 o: p. C }else{
/ O$ z# e7 {. T1 } X* _ $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
B/ y7 _9 u: J, T2 } }
: ?% R5 O8 ]: g! e! P $this->db->setModel($this->name);7 g5 A3 O4 A" N0 p
return $sql;) Y) s$ d3 @4 V7 P4 z- @" c) V
}( m$ p9 W3 R2 W$ A; w# D, P
* w2 N$ y+ t0 E3 b7 i
验证漏洞(举例): G/ v& c4 ?$ c7 X+ G) U9 M
请求地址:# |$ S `$ E/ _; M7 Q: p3 e( j: S
http://localhost/Main?id=boo” or 1=”1
5 F- ~# w L& v% k, J/ Q或0 S+ ^! h2 S: D
http://localhost/Main?id=boo%22%20or%201=%221/ A7 u" L g/ T
action代码:6 D8 v) C6 Z% G" O, k7 t2 C' q( l% b
$model=M('Peipeidui');
2 |+ @% r) n0 m $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);& p; S% o; L+ ^+ R; b+ r) E( L
dump($m);exit;
$ m$ Z4 k9 s6 ]: f" A# q. A或者; F6 W9 M% d1 g2 Q
$model=M('Peipeidui');
2 d( R& ]2 V0 `, B/ v* N $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
6 C* k' q/ @/ ~0 t! x+ B$ }, M dump($m);exit;- R+ _, T/ s+ ?6 U( \0 Y8 |& `
结果:
+ s% D$ O2 z1 v表peipeidui所有数据被列出,SQL注入语句起效., F1 g+ T$ L- B9 k! Y. d5 t
解决办法:. j+ K7 C! k' V: |! @- e
将parseSql函数修改为:* y$ H/ D, g! _8 ^& [# h
protected function parseSql($sql,$parse) {
% `4 p. H o4 ~9 a // 分析表达式
0 h' y; U' {6 ^! [ if(true === $parse) {- x: l/ t' L# X1 Y% [6 y
$options = $this->_parseOptions();; L1 M4 @1 ?. o1 c2 a' |
$sql = $this->db->parseSql($sql,$options);/ ~8 g8 X5 n4 `' ?- @; V, r
}elseif(is_array($parse)){ // SQL预处理! \' T2 _& P! D6 F
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
$ t* w0 _3 R5 r9 \ $sql = vsprintf($sql,$parse);
5 z% Y! y1 I: J3 y7 N }else{
- L1 y t! f4 j V $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));' I) ?1 l0 [+ q& r3 U. B
}
1 q1 |6 b% k9 ] $this->db->setModel($this->name);
( O9 e& g' U% p5 s return $sql;
' j( Z/ ], g6 L ~* p' V) v }$ Y# H% t0 k' f& K: a
* v! x: L8 }8 ?) k7 k& k+ L
总结:
+ f; L4 t( X* a! s不要过分依赖TP的底层SQL过滤,程序员要做好安全检查) C9 N t, q4 ^
不建议直接用$_GET,$_POST5 j( r5 I! L$ r" z1 K
[/td][/tr]! b4 y/ H0 `! k# S: }2 N0 u6 N
[/table]+1
) h4 D! s/ C2 n# W0 `, U
; E) z0 n( x8 Q) _1 {
( Z: ~7 O4 m, f! n4 a. i3 | |