下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
: x3 `/ h9 o. {ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件$ B/ D. Y3 O' Q( J: E4 B, w
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)) ]' a% O; B' k* p. f
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
( S6 p1 F/ i/ |" A# _/ Z2 F2 H$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
4 x* z, w& x3 f% E# A% r* |. @8 T8 I) T) `7 f* x% z) e8 `
或者
' g Z5 X* [) ~7 V3 i, i) x$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();' N! j. o, }' J: P$ A# _3 y$ q
" }9 |; ?0 N8 v9 H 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
' N0 I L, |4 X% f; Z( `3 s$model->query('select * from user where id=%d and status=%s',$id,$status);
; \1 ^! q$ H9 }$ l7 j' N! |5 @# Q& C( A3 x: j e5 q* D
或者
0 W0 {+ A. o5 u: I( X- o$model->query('select * from user where id=%d and status=%s',array($id,$status));% ?) x+ u5 t) M
0 x& Y) L# V3 S; Z1 U3 m/ Z 原因:8 a/ `$ Z+ C5 S( |- p
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.! P$ [/ O- D2 ]# t
原函数:, g& x2 x: d& n% J8 m3 h9 |7 W
protected function parseSql($sql,$parse) {
6 R& G7 ~# l J7 k // 分析表达式
" v @7 d5 e! s. J% E/ [6 v. E$ r if(true === $parse) {$ [/ {5 L$ ~9 U, M6 g+ O$ y
$options = $this->_parseOptions();
& w- J1 G5 \1 q, v, e. H $sql = $this->db->parseSql($sql,$options);
: x4 }# b* P- Q6 I+ W/ t) t7 h/ K }elseif(is_array($parse)){ // SQL预处理) R2 |% F% }7 o3 v
$sql = vsprintf($sql,$parse);; l: f8 x& Z( d
}else{
; h$ Y2 L0 y( a$ {0 X $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
6 k# _) s7 M# w! d9 q }
- @% H& n# l" \9 O) |2 ~ $this->db->setModel($this->name);6 c0 O0 R) i3 ^2 D
return $sql;- Q, ~+ f% }1 _' ~& _$ Q- I/ E v6 j
}6 b. k2 x8 j7 g; j) ~3 i' K8 U3 z
6 J T ~4 N8 N* \( g. a验证漏洞(举例):) C7 A2 r! Q. j% U# X2 Y
请求地址:
8 R$ X( A' \1 i# f. yhttp://localhost/Main?id=boo” or 1=”1
9 e/ G4 i6 c5 p7 m6 x或
5 c% I! O% h& o/ chttp://localhost/Main?id=boo%22%20or%201=%2213 u9 [4 k2 l) ]
action代码:
0 {7 x5 A$ h2 `2 b# S1 t$model=M('Peipeidui');( l& i* w; h* ]. d
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);% z6 b4 S' w p2 w# M4 a9 [- ~
dump($m);exit;
1 j5 M; v, T! r( q Q; a或者( D: r; a1 h+ R. G' D; A
$model=M('Peipeidui');- }6 p9 _7 G& j# h6 E! x1 H- S
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));7 o) ^6 q* x) l
dump($m);exit;
4 Y# h, S# G- v结果:0 O$ ?" k9 b1 f" t7 b
表peipeidui所有数据被列出,SQL注入语句起效.
6 `( ?; w$ T+ h& L3 q* @解决办法:
: P+ F- R( D3 K将parseSql函数修改为:& t+ W: L: b2 u( q, G( c# {0 J
protected function parseSql($sql,$parse) {$ C9 ^6 n& ^8 {- m c0 s
// 分析表达式
( Z9 X% Z& m, M$ G U4 ] if(true === $parse) {
2 }' @( Z, U$ E $options = $this->_parseOptions();
6 U. _6 {3 L% C3 W# h' g& p: l- Z/ d $sql = $this->db->parseSql($sql,$options);
( f$ `- u8 e6 D; P }elseif(is_array($parse)){ // SQL预处理8 q( H$ S# t+ [, x' k1 n8 G8 B
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码& g7 w3 v3 f8 Q* D3 G3 N- e
$sql = vsprintf($sql,$parse);
; c& I( I1 A: C9 d7 g! W }else{( d6 X# O! l8 \2 W+ \4 P6 W
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
! e5 \: G8 h7 S5 } }( @- ^6 D' ]; u8 o( [
$this->db->setModel($this->name);1 D4 I9 o6 X$ U
return $sql;
; D# O+ c. h: r9 {6 j }
% _ x! Q4 G8 d4 [. M
7 I/ j8 r2 x& O+ V! J$ m+ q+ S总结:& ] c; ^, G" @+ D1 o' r
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
0 |: v: P' N( k; _0 T7 C2 }, }不建议直接用$_GET,$_POST# L8 B9 r' T2 z& B/ U. T
[/td][/tr]
% Q% h1 Y! S* b0 d/ Q[/table]+1* {2 A! K% K. w# l" U
M- j" c5 y m
/ u$ B M/ b" T$ K; ~) Y) C8 E, Z
|