下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
* h5 l0 `2 s4 T8 ~# h' qThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件( V! P" h1 B) t8 M* K5 ?% v
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)* A: I: G- N8 c6 Y
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
! \. v- M4 j2 d9 H$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
; s' j3 U, }1 g( ]1 }7 {5 @
) {5 N7 f* |3 x7 O3 h 或者9 i: g5 B3 G: [% w8 N: t6 i
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
F- c2 C8 V+ m/ Y- M, [" z* }% G [ c |( x1 j, n
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):$ U1 {" I- _5 M' Y7 @
$model->query('select * from user where id=%d and status=%s',$id,$status);
. ~8 J" N. a8 h; {2 B/ Z, {; b; _9 e1 J! u/ Y5 B' v
或者! `. s& b5 t3 ~# w$ G: o
$model->query('select * from user where id=%d and status=%s',array($id,$status));
5 `8 a9 ]5 v! L7 f& H
4 ^. s; ~' @! f* v5 I7 e 原因:7 O0 ~4 }: z0 U4 V# B3 `6 s$ G4 v3 y
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
! |. R1 D$ t% v1 U原函数:
! p) n9 F/ m5 n, |8 l! Gprotected function parseSql($sql,$parse) {
6 V% T* v$ M# J; J( G p) i+ p; X // 分析表达式$ Y) t: [" r2 i7 A' v* f: H6 L1 O
if(true === $parse) {( o- y# E4 p1 G: F' x1 e
$options = $this->_parseOptions();
' `9 _0 G# o% d9 L5 q. q $sql = $this->db->parseSql($sql,$options);4 E! h: {' z# H, y# W
}elseif(is_array($parse)){ // SQL预处理
1 b O3 Y t- Q2 b# o* B; h8 f0 W8 R $sql = vsprintf($sql,$parse);3 o, Y: o: l! j4 k/ V. L- ^/ Z; r
}else{
2 k% K x ]1 ? ^1 `3 J6 s $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));6 v& {% @, m2 R% r& r; _' e
}; H8 l2 M5 V; e( ~# v
$this->db->setModel($this->name);
) C& A U4 |3 q' O# W2 {& ]9 C return $sql;
; Q8 U: u! C0 Q+ O }
- Q/ Z- \8 E4 @" N$ Q V+ }
) I4 k2 _2 G9 R验证漏洞(举例):* D: ?- E4 h. D
请求地址:
' x* `) c1 x5 @http://localhost/Main?id=boo” or 1=”1: k7 [6 Q2 \4 {1 ]) q
或. K! K/ L# ^# ?
http://localhost/Main?id=boo%22%20or%201=%221( d5 S) ?" j+ i" @' }" i5 l
action代码:0 l( |; Q$ C/ p, ~$ m
$model=M('Peipeidui');4 n3 N! G A' n6 b8 {" N6 O9 c
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);0 J/ |6 G0 S3 s9 h% Y8 d
dump($m);exit;# ^% Z; s5 J( L/ P4 _. n, b8 y9 c
或者) m' ` w y; k8 `
$model=M('Peipeidui');
8 F1 O% Z m5 t0 C $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
7 W. v- C2 t+ ^0 f" h; j dump($m);exit;; V* T" K6 w8 v" J+ T. r# s
结果:
% K. |- ]2 D& U$ H2 U; k' [* @表peipeidui所有数据被列出,SQL注入语句起效." S. n) S' b$ Z7 S- ^
解决办法:
8 y( h' y* A& @* |4 q: s- ~3 U将parseSql函数修改为:
1 t5 h3 y' h K$ ^2 e( N( aprotected function parseSql($sql,$parse) {
# ]+ t+ R: N0 v! W& y) K // 分析表达式( C3 f. c1 l! m1 l
if(true === $parse) {
2 Y/ S! i& R: m% E; l# N( n $options = $this->_parseOptions();: X) y7 G* E7 q6 ]
$sql = $this->db->parseSql($sql,$options);
- W) c% D+ I. F3 u& @# @ }elseif(is_array($parse)){ // SQL预处理( e- C5 a" T; a% c2 L% p- o+ E
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
# j2 \6 w, Z/ C* l $sql = vsprintf($sql,$parse);* v6 D7 z+ \% ~4 y; W: X
}else{
! _( ^& }3 Y% T; D0 S, w$ M, x, F! u" } $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
0 o$ z" W5 ]" |: D8 n }
/ S! b% P0 z( b6 d- s0 Z" h $this->db->setModel($this->name);
% J- u# K% y/ g$ ]5 Z return $sql;# n r. g/ s; h+ u) \8 M. g
}
$ _: E+ n$ B$ }* O) P# K* M. H. |
; Y0 R: i% ~9 q ]* P$ A' w总结:
1 A4 S+ K; ?. }: M不要过分依赖TP的底层SQL过滤,程序员要做好安全检查3 g6 ?7 s! w6 x, a5 Z% f
不建议直接用$_GET,$_POST& h6 Q! k' h: Z* o/ c- e. h& |# Q
[/td][/tr]
& ]4 `0 g+ I* B[/table]+1
6 i6 A% o. U% d' o; ?0 I
& ~3 k0 y( M- G( A3 ]3 z1 R8 P& `) `) X% `6 e* Z' G' ?
|