下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
7 G% r- |+ n B5 mThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
( Z4 o& u5 G1 k: Q* U+ t& T根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
. {9 x0 C+ o/ k4 P; }使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
" F) L6 q% B0 K8 {& `+ ~$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();% g( e8 k; p& H$ E. Z b: _3 i
/ T0 `( c2 T: a* x 或者. B Z1 J: A& a4 U) s+ _
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
) k' g* c2 v! S
: o% S5 V5 g; {$ ~' L 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
3 O8 u/ k* h$ X: e3 d/ u$model->query('select * from user where id=%d and status=%s',$id,$status);
- b0 h+ Y1 n" B- c$ c, u* ^6 r1 h; \: s* |( `% \9 x2 k
或者
/ U: Q+ K( Q; F8 \7 {6 }% u4 u; i$model->query('select * from user where id=%d and status=%s',array($id,$status));) u n6 w; o0 d& Y7 n K
2 g* u" ]2 R7 Q/ k 原因:. j5 {, k' W* L K$ R( ?$ J+ _; j
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
. Y, ?! e$ [, s! z5 i( X原函数:( X& k# D7 }7 i$ b1 Y
protected function parseSql($sql,$parse) {
& ?4 m) { { \+ F4 L // 分析表达式
0 i: M3 B' E( d# U# d0 E if(true === $parse) {
9 y- p6 ` O9 p D) n $options = $this->_parseOptions();
# F( K# U8 }2 C) w" w% v $sql = $this->db->parseSql($sql,$options);
$ u7 a: V; g- Z( n( g9 q# X6 D }elseif(is_array($parse)){ // SQL预处理1 t6 a; |6 v1 K6 h( |1 p
$sql = vsprintf($sql,$parse);" f! a2 n% h' v0 A* F% y4 n. W! S
}else{( ^4 w4 u7 q3 X9 q/ F
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
* B8 U$ W' z- z9 { }9 i. x, l* r% ~$ H
$this->db->setModel($this->name);" m D3 j- e5 @7 {
return $sql;
: a# h5 Q: v' c& x/ m( J# R" r }) W* H9 N" S g0 e
2 `) g! Z. H7 ^ J7 }0 }! E5 ^
验证漏洞(举例):
; u1 `/ t' @; L- Y: m; ]$ Z/ e& ?请求地址:
2 N6 `- A0 P1 M- l! P% Ahttp://localhost/Main?id=boo” or 1=”1
6 I7 ?, i) g5 E& r: Q$ F% m2 R5 G或. A3 d' k B% U9 q& B. f
http://localhost/Main?id=boo%22%20or%201=%221
" t2 ]* o+ `6 a" D3 q$ O1 ~8 Daction代码:
- ]; J9 }2 ?! I( c) ?, X$model=M('Peipeidui');
- u ~# o+ }, \2 i9 ] $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);* b0 f6 T6 j" ?, p' q' P
dump($m);exit;
) A F5 ~/ `* z! w' R7 M+ X或者
0 h- q5 W4 z3 I, ~$model=M('Peipeidui');% h0 v, ^; d B- q7 A5 w" ?( C
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));$ W! u! B& J* a' T; \; Q: o$ d
dump($m);exit;# b1 J' x& T9 v* K% a
结果:
2 r7 \2 t; T% v% F表peipeidui所有数据被列出,SQL注入语句起效.
# H( i' }$ m) Y, ~解决办法:
5 {, z; H, N' H* U% j将parseSql函数修改为:4 R1 Z7 X$ O% w1 t
protected function parseSql($sql,$parse) {* f, a, k1 | S: A q1 l+ E
// 分析表达式
# A' \4 O" \1 U- J6 U- [ if(true === $parse) {# {; @8 ~9 k. d2 T! v
$options = $this->_parseOptions();
4 W C4 H5 J& I$ a $sql = $this->db->parseSql($sql,$options);
% D; x* G- a4 _9 U- R+ N4 w9 Z5 h }elseif(is_array($parse)){ // SQL预处理
7 b) V0 o' b+ g# X $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
" I, z6 c6 I$ a0 y2 V y $sql = vsprintf($sql,$parse);1 Y: Q! B; w2 t7 P- Y5 t r
}else{
. U, Z2 b( A4 h1 u* b* D& i $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));! ]9 H* h- A' l
}& D: H+ A& u' D! Q( A
$this->db->setModel($this->name);7 P9 v* G2 o' m
return $sql;
, e! g; H. \2 |* D- J5 K& E/ r }1 u8 U; ~% w5 k- K
1 o7 o3 |* [$ t1 | C0 o
总结:
, R/ @# ] G; r, o7 g# s不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
5 y! W5 q6 K- S- p0 |不建议直接用$_GET,$_POST
b% Y& j$ q% ][/td][/tr] _# W: h) }3 Y7 G
[/table]+1) V, B3 g/ k7 ~& [/ d1 z4 X
) f- x& d7 T2 { Y8 K' k/ z/ d' Z: p, X, A5 R2 _+ x
|