下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。" d5 j9 ?1 u; M$ C
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
* |# _$ S U3 b根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
8 W) O! {2 j6 n4 M, P+ k0 z使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:+ n; J; k$ w0 V( |, B
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
! |/ e0 y9 c" D& h- j
; H) P. Y& ?9 _( [3 {! F 或者8 U8 ~3 k ^$ Q3 _. x
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();- k9 F6 M& F8 }, J) E' I
. v1 W: q! m D) Z+ X3 Y/ W9 _ 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
0 v" A9 h- k. d: `) N# \$model->query('select * from user where id=%d and status=%s',$id,$status);3 {' w. b2 n2 s0 g* z( K
0 C& U1 c5 U) k" w
或者
0 e4 ?& w" y3 E$model->query('select * from user where id=%d and status=%s',array($id,$status));
2 Y" H& F; k! R) g& g% \
& w% |4 u4 C- E, R' x2 b 原因:
0 x: }1 y, o# S& I& x0 Q PThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
: X+ V: F" h2 `5 r& [) d( X原函数:8 n! a; u/ l7 y7 P2 F- B" n3 \
protected function parseSql($sql,$parse) {( S3 q1 }: [/ V9 o
// 分析表达式
7 M7 g( {8 L; W% O if(true === $parse) {8 }) D4 X# o" l# n; K2 Q, _
$options = $this->_parseOptions();) D3 C0 s: y$ F$ y: `
$sql = $this->db->parseSql($sql,$options);8 C' y& \- e9 M$ j! b: X1 T
}elseif(is_array($parse)){ // SQL预处理8 E! ^6 V. o# |9 m3 _
$sql = vsprintf($sql,$parse);
: j5 t. C; ` S8 I! t* i# H- D4 k }else{
2 }" [. ?8 S% t* @6 j: t $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
& o+ a9 B* g' u: s, l }
! v( `+ |3 T3 y2 v $this->db->setModel($this->name);: x7 } k. ]: L' H7 @$ k8 [$ P
return $sql;+ R2 K- H6 {( m b; G4 ]0 U
}: r+ L F$ V( t* K2 x% ^2 r+ k0 i
9 |; s" ~+ B/ I( ~验证漏洞(举例): T: o6 a& V/ x( R4 S2 {# y
请求地址:) b1 _: v/ b# z+ j# ~- g% z
http://localhost/Main?id=boo” or 1=”1
, |& B# D) H i$ }% m或
; x6 y9 K3 B3 ~( thttp://localhost/Main?id=boo%22%20or%201=%221: u( C8 w% D7 Q! I6 Q9 l* e
action代码:
) i% A- q3 i! n1 s! B4 k$model=M('Peipeidui'); d% Y& w7 p( B+ a
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);3 T/ X. I/ s7 m# a$ L
dump($m);exit;
, T2 s6 Y h# D4 y( v+ i5 k4 _或者8 P. q8 D& L; R9 `2 S8 w: Y
$model=M('Peipeidui');
3 [) c6 E! P. K $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));) d; ]! [+ u" X8 B0 i" {2 ^2 e
dump($m);exit;. m/ b9 l- y# t0 Z: O
结果:
0 l* K' P9 N3 H2 Y& g' T8 _) W表peipeidui所有数据被列出,SQL注入语句起效.
$ f | N/ B0 [; P8 A6 h解决办法:
) y, X" n6 C4 Q0 d/ I将parseSql函数修改为:
4 w8 X" e; k6 J# z0 u4 Q2 mprotected function parseSql($sql,$parse) {0 }2 d) ?; s, G! E3 B
// 分析表达式& ~# h$ G' S# \5 U$ {$ a1 E) a$ M6 g, G
if(true === $parse) {, {) j* {; d3 B4 V
$options = $this->_parseOptions();
' q& d& D. ~" p) T% E* w $sql = $this->db->parseSql($sql,$options);' H4 }0 j. Z Y
}elseif(is_array($parse)){ // SQL预处理
' M( q3 P% b3 N1 k$ [$ W: ] $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码" }4 E. @/ e* t f: N- f6 T
$sql = vsprintf($sql,$parse);
' Q0 h" ?0 W R- l# ]/ i, \( | }else{
7 E' \5 T" s0 X4 j $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
* [. R9 \ h# F; L& I# u }
5 ^0 a$ e7 p3 J- y' t $this->db->setModel($this->name);
4 k- U4 d/ i& Z7 E2 L' _ return $sql;; x$ A& ^/ ]/ y8 L
}
' X Y. P9 X/ L: J
) X( N' M$ A, o$ n3 m+ |2 C5 T9 h总结:
. d2 U6 s4 I5 b* }# p7 Z K9 x* U! I不要过分依赖TP的底层SQL过滤,程序员要做好安全检查4 y; ^1 K9 @; j5 N: S# X6 Q- r
不建议直接用$_GET,$_POST( U- X$ J. z4 C7 K' d' ^) @1 H0 {6 m$ m
[/td][/tr]
1 Z/ n& g0 E! N; J[/table]+1
, A7 a' _' r( I# \1 N& G1 S$ i* T, H+ F2 T
5 |. ^4 p; @3 m; K- P
|