下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。3 y; q9 F. J# R+ d5 S1 O; p
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件4 n, X0 W4 A# X9 X `9 c) m! M4 g
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)$ y8 R1 [- L1 V! O, X" w) W
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
/ b9 e! I" ^5 ]5 _$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select(); _1 v* G) s9 i7 A, U. k! i
: ^- _. F& b, q7 B/ W" E
或者3 m1 d( b% Q* g8 k6 R+ D0 \5 V
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();2 |* E1 D3 u! s1 Q- V8 B3 c
% P# j1 ?% k% ? 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
" O9 @0 U; V, A! \$model->query('select * from user where id=%d and status=%s',$id,$status);
' Y6 x( G4 \1 Q& t4 w- S. S6 g; P* J3 W C
或者
# y5 A* D8 `& t# r, I+ W2 o$model->query('select * from user where id=%d and status=%s',array($id,$status));. F0 `! K, F, N# p$ w
, D# F F, P) R 原因:
0 q1 x( \- o( xThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.) P& p( {2 {3 g
原函数:3 w% ~& t A: y; N H; p, @
protected function parseSql($sql,$parse) {
9 ]" M$ l$ N% |6 ]# O // 分析表达式
' I2 E w. w/ k if(true === $parse) {
: ?4 u, r/ D7 ?8 j2 a. G $options = $this->_parseOptions();
$ Y- G4 f, G/ f/ ~ $sql = $this->db->parseSql($sql,$options);+ D$ L; I1 ?, n D, I+ W( q
}elseif(is_array($parse)){ // SQL预处理- w/ B5 B& i1 {6 P
$sql = vsprintf($sql,$parse);) Z$ Q! m0 b% t
}else{
6 [% P% p) E+ U/ V' h! D( P! D& b $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));. R! O+ Z" N1 A$ i# a, W1 E
}" L. r" H1 B5 c' {
$this->db->setModel($this->name);
& J+ f& x3 Y4 G+ e. K2 m, @; G; C- e6 T return $sql;
4 Z6 [* O; q. W" I- Z }
/ h! A ^0 B6 U: G4 @: L: K' |5 Q
0 T4 b2 l& H& V: g x" e5 o验证漏洞(举例):
( U+ j2 E# h) e, F* {) w请求地址:8 z! n+ w1 J" P
http://localhost/Main?id=boo” or 1=”14 T _4 V$ d' f' E) Q/ p9 ^
或
5 R( r2 H; ]" y8 c8 [/ phttp://localhost/Main?id=boo%22%20or%201=%221( ~ g+ a% f; M; D0 V: N" `7 z
action代码:: ~, d8 n8 H1 l3 v
$model=M('Peipeidui');1 u1 q7 W! i M7 C& ]: y5 l( N0 v2 [8 {
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
% J5 M6 t8 z X; a dump($m);exit;
5 A% @3 \1 S- E5 _! I或者# w' l6 D" n- c0 ?& l! X
$model=M('Peipeidui');
7 a" U& Q ^- [ $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));* P) l: f: s; V+ }& ]: o) h
dump($m);exit;
( c- s/ H& p. Q+ a5 J" D结果:! X% Q' n( m4 f7 h9 g
表peipeidui所有数据被列出,SQL注入语句起效.8 a$ D0 P0 I! S& {
解决办法:
U( W6 V- W8 ?& K' O3 x将parseSql函数修改为:* [+ k' f. Y* Z- g$ \* L" v) F
protected function parseSql($sql,$parse) {
# y0 l$ l7 A0 X& H2 F9 i' ] // 分析表达式
$ C* ~" D) y# E' ^' H' ?1 s if(true === $parse) {
8 j q! y; c0 Q" }5 N* b $options = $this->_parseOptions();
( D: j. ^) K0 Q! }% [2 @7 E $sql = $this->db->parseSql($sql,$options);
/ I. X$ |2 r) O s- ]8 }# @ }elseif(is_array($parse)){ // SQL预处理
/ G: u+ y6 x+ h/ C& p8 @3 E $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码3 A1 [( y: d4 ~3 c9 j6 M
$sql = vsprintf($sql,$parse);+ ?7 E7 b- b+ W
}else{3 v. q$ i0 g$ ~
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));5 l, K- K; y- X$ F- }
}* c1 ~; N( p* |! |- z" q* D
$this->db->setModel($this->name);+ A: g0 A- c3 y, ^- Z2 S* `
return $sql;
X7 b# p2 f# k }
( r8 o' Y6 q3 }5 E, |+ F# J& a+ m* s( k" i3 F8 o
总结:
& A, s5 w5 {" S( v; A% |2 G6 P不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
) d; t3 F8 H, |0 s: I2 Q不建议直接用$_GET,$_POST
) W; u, S9 f+ U2 p( N1 z6 ~[/td][/tr]
2 x: G% a" ^1 v' Q[/table]+1* f5 y9 n6 e. p! C+ [9 O: o8 g0 Y
$ R- N2 o, ?" U* z. f
* ?9 O I2 [% m: u- P( n& ? |