下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。7 ~. ?7 o5 c2 ^
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
' J6 Y4 v! C9 |. ]根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
|8 h, t8 R& N; ?" z使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
) P8 C; I9 z0 V+ Q0 ?* `$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
2 l7 c6 U9 r0 ?& e( g* L4 R B& a
或者
' o; |" o4 k2 C5 a$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
, F" H- ?9 T. Q- R" l9 Q/ X* f6 M. l. v
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
6 R4 p, F6 N. w6 R. h" H; n$model->query('select * from user where id=%d and status=%s',$id,$status);2 w: v! g7 V1 y* y3 d" n
( z4 A9 y9 W9 a& O或者0 I0 s+ Y2 U! \2 t! H
$model->query('select * from user where id=%d and status=%s',array($id,$status));
; J; |) u! }6 O0 I6 m+ u3 K, h
& M0 Z: l- e" y0 @" T% t 原因:
3 S% I& u, o. w9 K k# {" EThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.' M0 }2 ?3 U( E2 N
原函数:# I" J. J" V$ G- n
protected function parseSql($sql,$parse) {
) L8 o2 h" T2 X5 T$ A // 分析表达式
+ A1 A# V. J$ j8 A* U0 U if(true === $parse) {
; u \& f! R" e' d% L8 Q $options = $this->_parseOptions();/ C# _5 v3 v+ w; [9 c
$sql = $this->db->parseSql($sql,$options);5 f7 V/ ^: x$ y/ c7 Y) B, f
}elseif(is_array($parse)){ // SQL预处理- Y7 k6 s6 B, a. A ?2 @2 K
$sql = vsprintf($sql,$parse);
$ W4 ]. @& c, v4 X }else{+ W, C) u: z6 W: k
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));* S6 x- m2 Q2 n ?. M) n+ W
}0 H2 F! ~8 t) R% Q
$this->db->setModel($this->name);
( y! o1 N9 w9 y5 m* b return $sql;6 J! Q7 {+ m3 Q6 g
}
. R7 ]' P. J+ w7 u* V. v- I: X; J* A' P9 j, W9 ?& ^7 Q
验证漏洞(举例):
7 J) C9 _- T x8 j8 ^请求地址:# z2 t% H9 H$ a: ]" ^* `. W
http://localhost/Main?id=boo” or 1=”1$ J9 ]+ V5 p- U8 R/ M5 ]; Y
或
0 [3 g4 ?( {9 L# J5 i+ y5 Z! lhttp://localhost/Main?id=boo%22%20or%201=%221! ~$ q) b" Z" Z/ P! ?- @
action代码:5 j# Z* B* s- y# q5 ^
$model=M('Peipeidui');
" \' W% D$ W2 s9 Q) X" ^$ S $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
Z/ _1 e: d. E N3 q. g: N7 c8 b dump($m);exit;7 V( L' |4 _* p0 Y5 ^
或者
* ]/ Y0 N" N! N0 y$model=M('Peipeidui');
$ `; F. ?6 S/ m; L0 a. r $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
2 {( t: W) L) @4 ^+ k; [1 p8 ` dump($m);exit;& h9 A( d4 e/ f0 R
结果:
9 M& B6 i V9 ?! U& m表peipeidui所有数据被列出,SQL注入语句起效.7 L# u7 w) W: L8 c, _0 @
解决办法:
0 \ R- [" k; y/ l) Z将parseSql函数修改为:
# c4 \! A$ I: j3 z8 e+ jprotected function parseSql($sql,$parse) {
9 r! N# Q: E, C! r# ` // 分析表达式) Q: N# o8 r4 `0 z" k, }
if(true === $parse) {
& s( r7 w/ P7 N0 {* c; W $options = $this->_parseOptions();9 f, ^$ ?2 I- W6 ^
$sql = $this->db->parseSql($sql,$options);
/ L$ F$ @) I' A- {# @ }elseif(is_array($parse)){ // SQL预处理) T0 U0 }" |9 u, C1 N4 m/ ^; K
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码4 j, ~) Q, V! v
$sql = vsprintf($sql,$parse);
& i& I! J9 @) | }else{
1 a8 |% \, T- K6 r+ P* L $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
, I/ l2 c: [8 v) g5 U/ ?+ ? }
) P+ C7 E( c/ D5 `! G8 z $this->db->setModel($this->name);- e$ K! `8 Y: K0 o
return $sql;4 T4 R, t# u& Q6 F6 `
}' X9 J6 z( U: V% z# x2 i" V
8 z8 ~( ], |( d. \- ~
总结:
3 c$ f. K8 i8 l% Z4 t( M7 q# z2 p3 e不要过分依赖TP的底层SQL过滤,程序员要做好安全检查7 k( v- n1 l, ^9 j7 I
不建议直接用$_GET,$_POST5 L) ]6 y& y1 Z6 l6 a/ U
[/td][/tr]: ^- J3 x O. h- y
[/table]+1
- ?/ V v6 e9 h8 G H9 R# ]( b3 U/ V- x+ L# F
8 p4 ]' _# `7 t8 v ` |