下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
, d4 y+ \- L3 _" y. K" Y3 w$ M, zThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
4 U: L; }) s% o( ^根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
3 t" P1 i$ \' S: Q% ~( i* p, z+ E" I使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:9 \# n4 z+ K* _, V, y" O9 o' L
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();/ `# c* I+ | W/ k
0 Q ? A- S& q# o 或者
: D1 ] X6 {0 v& v+ u7 U* B- E$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
# I, E# T/ l+ D7 l. N9 H& E( W. b2 F: s: B
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):% V7 J; a% Q/ n' B" b8 g
$model->query('select * from user where id=%d and status=%s',$id,$status);8 S# g% _ o8 ?0 n5 I/ C2 K4 N
# w! v$ \7 b/ r" i或者
* e% ~' O( b' Y' ~! q* O, M/ D4 K9 ?$model->query('select * from user where id=%d and status=%s',array($id,$status));
9 g9 s$ {6 T7 A6 x9 B: O) u) ]; e( r) s# X. N. W
原因:3 X2 u) ~& ^3 H5 `1 I& v/ a
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.' m0 p6 Z/ k# x2 ?
原函数:
4 W5 w& [( C, e5 Y. i. f7 k7 dprotected function parseSql($sql,$parse) {+ D& q* a6 Z: {8 z
// 分析表达式 F0 L# P3 u& H2 C; m
if(true === $parse) {8 p3 w5 C! F) c! w Z$ ^! q& q
$options = $this->_parseOptions();
* N' d, q( i7 v3 [ $sql = $this->db->parseSql($sql,$options);& t! H# i+ x4 w& Q7 A
}elseif(is_array($parse)){ // SQL预处理' y( `6 l4 R* `" x# K6 n5 `! i% u7 F
$sql = vsprintf($sql,$parse);
! P5 r& x0 n. q2 k9 G }else{/ c$ H$ o' j, Q2 S2 x( C1 J1 _" a
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
4 @" a- e- W# b5 a* J0 T }
' ~- X. v# T/ d7 k$ V $this->db->setModel($this->name);. E6 p2 O& C( v
return $sql;
+ v) ]9 p9 y9 o* k5 G }
: }$ F: p5 _2 ?/ o2 r- K( S
& @# b& A* f$ }5 }, P+ R验证漏洞(举例):
4 i- c: S N8 U' P请求地址:$ C3 F9 o+ ~2 l
http://localhost/Main?id=boo” or 1=”16 M( T6 C& z# m6 v9 R( D
或
1 g) f, g) a" H% L) R5 lhttp://localhost/Main?id=boo%22%20or%201=%221
0 {( G' F. f# \/ a4 R( k; xaction代码:: a: z! C0 Y* Q" }4 ]# I; t
$model=M('Peipeidui');
8 H, y4 _) U- _! K/ \ $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
* z0 q: |. [+ H7 d8 n, p" c- l8 _ dump($m);exit;
! G5 D. g0 H% M1 ~$ G或者) I& E+ Q: ]8 t7 U7 ^
$model=M('Peipeidui');$ ^; r) y( M4 p- p0 H
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
0 a. E+ r, X& J1 V4 _. r dump($m);exit;
( Y( N5 ^; M& _! x3 \结果:
6 \! S6 l9 ]5 l. V表peipeidui所有数据被列出,SQL注入语句起效.
# z- Z% I8 ?6 y' I& F1 \解决办法:
4 Z& x, [2 f) g7 \9 L8 V# g" k将parseSql函数修改为:$ S( |- W1 Y4 E8 ]
protected function parseSql($sql,$parse) {& i' w& y8 v Q. O m1 }2 v
// 分析表达式4 \7 z3 w; c+ N3 v, @ Y: M
if(true === $parse) {' ?5 |* X* q3 F' I2 N" o# w+ B
$options = $this->_parseOptions();# x) t# A. u& E$ ?6 O' E$ |$ `
$sql = $this->db->parseSql($sql,$options);
- l' r! L5 O" {* R0 D }elseif(is_array($parse)){ // SQL预处理! h' n+ p4 M" N1 N' b7 r
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
2 G4 z* q4 j. }% Q $sql = vsprintf($sql,$parse);
/ }6 I, r" x$ G/ v5 E4 r8 Q) E/ i }else{
1 j: U( o5 k. Y/ g: E $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));! B% s! P7 s9 W! M; S$ \" y$ U( q
}. r5 }8 x- O5 F7 [$ G% d5 X1 l; M% x
$this->db->setModel($this->name);, \" m4 N9 `0 H
return $sql;; ?# }* I- R$ F9 g4 }- A3 m
}4 I0 V4 ?2 D, V
c# L( q. ]& V/ [, Y* O
总结:8 g0 X9 z. G* }1 n0 V7 l: N7 Q
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
% i2 r0 o; D6 i g2 j" r$ p不建议直接用$_GET,$_POST
7 W) ~/ t; ?# h4 N# Y u& L[/td][/tr]' r) ]: v& M& s9 X" u
[/table]+18 `( T+ r- S9 ^! d8 ~! L! P% R4 j) u
u4 Y) @% u% i6 u. i
- J2 d; M4 W- C+ u) S: u8 e2 i |