下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。$ t% q; H- S) N0 D8 r$ z* }
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件 r t/ P6 ] v T
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)- u7 C, r2 ]2 x( I; S' M
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
8 q7 o# f2 m- s& E9 P2 z$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
~' M) L6 o; P, X" o1 S
+ R1 u$ P: O. V5 { 或者
2 R! ?+ [' [) f+ d$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
: E/ Y5 @( n; e' g7 h; m! q# x, I3 a1 ]" N9 {: K
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):9 s8 P/ X2 A* C! k+ Z9 g# _
$model->query('select * from user where id=%d and status=%s',$id,$status);
2 G* x/ P* ]& I' C+ Q2 V- m( `
" m6 a- ^2 O0 {* [& r# E& [+ _或者" i( q9 |* c7 g# n) t
$model->query('select * from user where id=%d and status=%s',array($id,$status));
# E0 U+ L& h/ G9 K) y& f6 `6 T" l+ n+ x/ _' a, i5 A/ a
原因: |( }6 t1 ?2 p+ ~2 B0 m3 Y5 }) Q
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
3 @ ]# f4 s" [" C4 f原函数:
1 \& r( m- ?/ @& I0 f6 O! cprotected function parseSql($sql,$parse) {
; B7 u" n8 u5 t% A // 分析表达式. K. O( _( W3 [: z: ]9 p, X c
if(true === $parse) {6 B \+ p" I5 @1 p! U6 G! u
$options = $this->_parseOptions();! b* U/ q0 }- {! D
$sql = $this->db->parseSql($sql,$options);6 `+ o$ |8 r' I
}elseif(is_array($parse)){ // SQL预处理
+ [1 Y4 h9 Y: M* \$ c $sql = vsprintf($sql,$parse);
$ }* u' i, c7 x I M( a9 O9 F5 N }else{# [' k7 s- r' o* ]
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));% B( Z' B) a4 R
}8 l" k( B' f) P
$this->db->setModel($this->name);
) R" l7 [( G+ D. s3 J* j return $sql;
) M+ U" ?' D7 W+ y; G }
) l' L; Z9 [1 A4 S. V5 P! K/ Q* M
8 W' S) p; Q8 H! {4 V验证漏洞(举例):
1 G: l. U# n* r7 S {请求地址:
/ B; M; s$ }% h1 E3 Khttp://localhost/Main?id=boo” or 1=”1
: r3 b. r! ]( e' t0 w, L或- h* _- h+ A7 T' g6 K5 q
http://localhost/Main?id=boo%22%20or%201=%221, ^; \( V/ j4 ~9 h' t
action代码:
( i z) {1 F% F' v5 X5 y$model=M('Peipeidui');
: ~! T& U$ D. \9 x6 e c $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);7 j/ _( X' y/ a4 f" g) l
dump($m);exit;" e7 D4 ^/ B* X
或者
8 D, T, o' d$ ^2 t$model=M('Peipeidui');
3 U: m! d3 O' B, q) H1 T# N& ` $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
* \* O, p2 m' t1 Y dump($m);exit;( Y0 x0 x( N( C
结果:
; G' b' ]' M3 f' \7 q( H& N+ W b表peipeidui所有数据被列出,SQL注入语句起效.# ^( R4 c' }. X; E R* ]
解决办法:
' g( I; A- U6 ]% J- \将parseSql函数修改为:
# {4 G9 V. ^& a3 tprotected function parseSql($sql,$parse) {
0 p& p+ e# E. F8 D% |# `% ~ // 分析表达式) F! I8 T& }" ]5 |+ W1 y& U
if(true === $parse) {% n D/ D4 h5 K- a3 B/ n# j
$options = $this->_parseOptions();4 A Z1 p( v9 x5 ?; m1 s- `8 G
$sql = $this->db->parseSql($sql,$options);
4 r/ l# ^, E( S' H: L d }elseif(is_array($parse)){ // SQL预处理
8 a2 M8 m6 R0 f7 ]- |# L% ]9 E $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码1 J8 \: F8 g5 V% U* j: g# }2 P
$sql = vsprintf($sql,$parse);
) l( u, v3 W/ K; o6 p }else{, X! ^ w9 y+ T! t% N
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));4 ]6 {' i- n+ s, X R
}
% l: B1 K: L+ k $this->db->setModel($this->name);6 _" U. q$ F0 y' ?3 q
return $sql;
) U# p5 V) w7 ]/ S7 p+ W% H }
6 x7 Z9 ]# Y- Q2 W/ \9 E. k4 f% X* C8 c6 M) \$ w
总结:
" n6 o5 |0 J2 L6 i( z不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
/ g( y3 Y* p6 r8 Y3 e; g不建议直接用$_GET,$_POST
9 ?5 g- g, O8 p. [) z[/td][/tr]: J% v, `1 E0 j n6 o( k
[/table]+1
3 N9 V0 I1 \( z/ C+ g+ }6 E, L& c/ {$ @$ T: r; O& I
6 x& s* i: [6 }7 C- H7 s; l |