下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
' @9 q% `7 ?' K+ z! {% _: KThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
b% V" b: ?1 q2 c根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)' s4 y; @) C! L2 {+ J, s
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:; j: e! B; b) ]. Y
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();+ P6 Y( z! K# @# e# ]2 |
! S' Q; w/ u3 O* F% L 或者
! ]& `$ [6 ~# S9 m& ?$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();9 z# Y* t. m2 f6 s2 a
! G( n1 x6 Q2 j, `: [+ U7 Q# Z
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):0 ]3 f+ P, l' w5 u
$model->query('select * from user where id=%d and status=%s',$id,$status);$ e# |, a, ?7 ~. a
+ c6 Y4 o8 z/ q: x7 \, ]
或者
! W3 B1 O3 F: m6 d+ H9 L$model->query('select * from user where id=%d and status=%s',array($id,$status)); v. @% L6 W; @! Q6 u
. `8 y. \1 c, j+ f* W 原因:
) C9 d8 ]9 J0 i9 `/ yThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
3 C2 T4 u3 ^* L1 [3 k1 a原函数:; z1 m# }! ?. B0 B# D# B8 p/ d
protected function parseSql($sql,$parse) {2 X: B4 D- L% q% p# S
// 分析表达式' D3 ^. z7 n4 L" E4 C7 `
if(true === $parse) {
; q- [8 C( w4 d $options = $this->_parseOptions();
+ X, k0 r* _) ` S" q }* K% ~- p3 ~ $sql = $this->db->parseSql($sql,$options);4 z; p4 l d$ B; e, l
}elseif(is_array($parse)){ // SQL预处理
& H) P; [1 x, q8 G" T $sql = vsprintf($sql,$parse);
' r0 M/ t0 }/ s& G5 V7 H0 P }else{
) V2 o# @! S) X0 Y $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));1 X$ S8 A* q q* C
}
+ h! u3 P- o0 D7 I6 j, H) } $this->db->setModel($this->name);
! e5 u+ T$ n" ?; A4 [4 [% t+ H return $sql;
8 ]2 c2 a! t8 ^ }# e0 w) ]. a# ], _. r! c/ R
& ^% C) G0 K$ \6 X验证漏洞(举例):$ k- v4 J. r# j% a! Q- ~/ d
请求地址:
: D4 a* }, H% m+ j2 Shttp://localhost/Main?id=boo” or 1=”12 j3 r: V/ A" D' ]% X4 H
或
" S! s( j8 b# g5 Bhttp://localhost/Main?id=boo%22%20or%201=%221
8 p t, I) y. B1 `3 w- Z3 E( R3 B$ waction代码:
* h; n$ L6 W. I; @+ p$model=M('Peipeidui');
: n3 o6 f, ]3 ]1 R! i $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
1 g: E4 J5 ^" }) }. Y, _ dump($m);exit;5 z. l$ t8 B+ X' n# O8 O7 H `* L
或者
. M1 [+ W6 C' H# U0 p3 I$model=M('Peipeidui');
- I& H" {8 E7 d1 Z $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
% M; m& v6 `/ v! \0 d$ w dump($m);exit;
5 s* Y; C$ b* j8 E9 W" V( J结果:
& f) _ l! u" O0 l' R- X; c) a5 j' S表peipeidui所有数据被列出,SQL注入语句起效.
8 W+ `, u$ v5 D! P) R1 T! w9 l1 `解决办法:! k( ]! K; M; x5 B% {
将parseSql函数修改为:
3 Z) h( k+ Z& {" h1 c4 Fprotected function parseSql($sql,$parse) { ], E8 N4 @ K' q% n" J
// 分析表达式
% f: j. ^7 ~# U/ R0 d if(true === $parse) {
% X u' I% e( R- ^# D $options = $this->_parseOptions();; a7 r* E+ r S+ I* c+ ~/ o0 n- G
$sql = $this->db->parseSql($sql,$options);; X3 a, {* G2 E* j& D+ Z
}elseif(is_array($parse)){ // SQL预处理
. }+ x6 i8 x0 \" N3 ?8 E# T- I- s. | $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码/ l, K! I, G. ~ u( J
$sql = vsprintf($sql,$parse);
7 \' Z: f. }# i& S }else{
- Q; F& i# K. F $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));) i0 e, l7 [7 z) y4 i# |! m2 t, K% p
}# W k4 I* H: w" P9 [3 Y" {
$this->db->setModel($this->name);
5 Q) N, w( l0 ?- G- f% Q5 ~) t return $sql;
4 N$ D: f$ f1 a/ l, l; }% s' c }; k; ]1 f. J) e% L2 B' L
% ^7 t( t, m7 [3 N- V; i/ i, L总结:
5 d, y( v( I6 o9 L- H! j, V+ R) V% A不要过分依赖TP的底层SQL过滤,程序员要做好安全检查% z7 A# j% F Z: d0 Y( N
不建议直接用$_GET,$_POST
0 o. f' z5 Q* B2 P& a[/td][/tr]
& g5 j, w2 ^' Q[/table]+1
) v, O& L1 N$ D7 V3 w; V+ d0 e; y& C+ V2 [
* {' U1 _/ v9 f K I' P( Q E) g8 | |