下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
( w( S$ G) ?. b- Z" ^: R0 lThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件9 l5 b1 @- x5 Z) G9 ?
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
6 Y% E; _, m' o! _9 U+ Y# r使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
" U+ _6 H2 p4 c j5 R9 v0 i/ w$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
. L) k) @: l5 u6 r
; ` ? V9 L" d$ t# b) h 或者
! {1 R E/ ]- C- s$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();; O7 C' }- K& |
( r3 ^8 Z" _5 Z5 d 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):! m \% T" A" ~, `4 \
$model->query('select * from user where id=%d and status=%s',$id,$status);* M; S$ i4 e; }& ?7 Y9 @/ W
; o1 \! j: n, I8 R; d l或者
1 D4 K$ Z# D- T- x& z( o$model->query('select * from user where id=%d and status=%s',array($id,$status));7 S4 x3 Z$ g+ ^9 k
4 G$ i! ?' I1 l5 D; c 原因:
; h9 E- Q( i5 a# j8 ?0 jThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
) w2 n/ }# l' o原函数:0 Q# ~9 h, M) J
protected function parseSql($sql,$parse) {+ _ w0 n: _0 _1 r1 e+ t; N' i
// 分析表达式1 p1 f# y, |1 o$ I! ~/ g
if(true === $parse) {
) w: H: G( e1 V) ` $options = $this->_parseOptions();5 g/ ^, H4 |: w9 ^% Y6 B6 C: Q2 |
$sql = $this->db->parseSql($sql,$options); r& X5 {1 C4 y) O
}elseif(is_array($parse)){ // SQL预处理1 z# d: ~+ z, j+ C! r- ~
$sql = vsprintf($sql,$parse);( L3 s; c) u1 G# i
}else{
! L$ ]( ?; t" c* l% b $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
" f) {5 W& ^9 \, n& x }
1 g7 A) a7 L& e, Q( Y# {" X $this->db->setModel($this->name);8 b! u+ p9 ^1 d* q& B. A* p5 a b
return $sql;4 x- W: z8 U/ G8 s& ~
}! e% @3 k' E/ K! V
; V0 c% o7 G* e0 n/ G
验证漏洞(举例):
+ ^; }, g# v% [$ T请求地址:4 `# q2 z! V. A& {( v
http://localhost/Main?id=boo” or 1=”1+ k3 w8 I7 ~3 t t6 P
或) b% R+ W( Y4 S) k2 B& p
http://localhost/Main?id=boo%22%20or%201=%221$ s& I7 [1 g/ Z7 k# Z
action代码:7 k: p, k( Y: M, w5 X
$model=M('Peipeidui');
- x9 K% {- @3 B2 }0 g $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
' R0 J1 p7 B! Q' T2 P+ G' | dump($m);exit;
/ B9 y! L! H0 I或者$ X9 m7 O3 I+ i% _% i+ k% K
$model=M('Peipeidui');
8 X6 H Q7 f# b" c $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));# }3 Z& R7 B7 r1 S3 Q" j/ `. X
dump($m);exit;7 r- |9 J, V; N; R! |9 v
结果:$ j+ _) |4 b, ]
表peipeidui所有数据被列出,SQL注入语句起效.; \8 _8 M" p+ }* s
解决办法:' f& A$ C* e% J# n
将parseSql函数修改为:0 ]5 h1 ]0 w: U" ]- b* H
protected function parseSql($sql,$parse) {
3 G6 K: {2 g* J4 R3 O* r, Y // 分析表达式
& I0 s3 r) w( ^. F: D: l: ~7 | if(true === $parse) {# ?1 W6 G, a$ D( z3 _) }
$options = $this->_parseOptions();, s8 ~3 m, R7 L- r$ H
$sql = $this->db->parseSql($sql,$options);
; \9 p2 O! U' @% p. E4 l }elseif(is_array($parse)){ // SQL预处理! a( t! s4 L/ {
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
4 U. h$ K- M) r5 | $sql = vsprintf($sql,$parse);
! C1 e4 A5 u3 C9 j* b9 `+ L$ H }else{
# G0 A* {, m& I* U2 Y $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));* K1 _7 b. D1 A2 f5 H1 `+ A! m
}. K/ f1 n- W" |- j; `
$this->db->setModel($this->name);
; n6 u9 N5 G) z9 D- p return $sql;
* e! l. C' L' y) e }. d$ |1 f' k9 V" l5 j# M
2 D# h& m$ [! t
总结:+ p* E7 f; Q5 k4 E9 @
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查' K$ n* D1 P; r
不建议直接用$_GET,$_POST" ]( L2 p" E, G% \& u
[/td][/tr]
7 ]7 @8 O9 J! Q8 S& ~ m[/table]+1& [+ L* \1 G; c, H1 o7 X0 g$ \3 |
" u* @! B9 g) A; X; x+ `
8 z& p3 V+ A$ c* q1 _7 m- l7 ]6 H |