下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
) s8 G/ b' V9 U$ \: M. t9 C0 X0 TThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
; d+ N# n1 c, r$ r根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)5 u+ j# b4 j; V0 Z( d3 S
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
' ~! A* Y/ z1 m+ }$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
! R! {/ N) L7 _# z2 n1 `' x {, [& i
或者% f/ f1 q! D' N1 B0 Z5 _1 U
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
: d: o8 f' P* u9 m( I- Z- i" a+ d2 Y* r; C5 M9 D, W
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
3 V, E! s* A7 Y$model->query('select * from user where id=%d and status=%s',$id,$status);
' e/ W* I7 A6 z" v6 z& y5 ~) B, r! S0 t9 p6 _/ W7 t8 W
或者
* B; t1 k# K+ k7 o' F5 f; q! ~$model->query('select * from user where id=%d and status=%s',array($id,$status));
" x; Z: c: P( n* ] |7 _* K
" o" u$ f# n! Q' j1 i, s8 z 原因:
) g' a6 C% H5 ~* K- n4 |ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.- P( M/ n4 A5 m" W
原函数:- |; A( {1 s" @3 L6 }& e0 X
protected function parseSql($sql,$parse) {- ~6 p, A9 W0 m) Z" i
// 分析表达式2 L1 \0 a3 m/ `7 k @) f
if(true === $parse) {
, \. p8 A7 R4 h $options = $this->_parseOptions();
% _) a* \4 H8 J; g, G) ]! y $sql = $this->db->parseSql($sql,$options);
1 G9 e0 I0 F, @, ] }elseif(is_array($parse)){ // SQL预处理
x- {! x4 O. h# R5 }. ~: Q6 P $sql = vsprintf($sql,$parse);
# l# S7 t, b( h }else{, J: s: p. t R7 l5 H, ^
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));5 n# E/ ]: l' S) q3 B, D6 c
}, H+ I9 E4 t5 X r- o# F
$this->db->setModel($this->name);
, `& K: A; O: O. F# D return $sql;' s" R) a+ N( M2 _: G8 c
}
5 l4 D9 K3 ~8 P5 [ L: u' j, g: }4 b) ~8 a; v+ h4 e6 x
验证漏洞(举例):. ^4 _& ~1 j$ Y' S4 f. t
请求地址:) Q2 ~6 X1 N# L, F- L4 ^
http://localhost/Main?id=boo” or 1=”1
" w4 B6 x# _5 `, U或& q% K- }+ {6 a! @$ P" b
http://localhost/Main?id=boo%22%20or%201=%2217 l0 f9 i$ J+ q I+ J b/ p+ e, U; g% [
action代码:
4 k+ U9 f0 n |4 M$model=M('Peipeidui');
( |" X3 \, r0 a8 P0 J0 J5 a $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
. B6 `( \8 p3 v* } dump($m);exit;
- r6 ^) r* n# y; O或者. u: Y, B2 k2 S- [9 L8 P) z& Y2 `
$model=M('Peipeidui');* l. @' C' S' G* }1 A( T4 M U
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
5 s1 g, [7 I$ Q) V2 l: x7 T+ \ dump($m);exit;
& N+ | T& q$ M; z Y% `结果:
1 n6 }% O5 m7 G4 A; K* D5 s& z表peipeidui所有数据被列出,SQL注入语句起效.
3 h; r; r$ n5 c5 Y解决办法:3 I) B! ~, W+ z/ ?8 J$ v! S7 i
将parseSql函数修改为:1 x; K7 ?# T+ @; B5 A
protected function parseSql($sql,$parse) {
' e0 ^! R4 u/ m( C7 Z // 分析表达式" }1 e; D" `5 V; d
if(true === $parse) {1 N; | `: |9 J9 Q, w' ~7 q) t2 I
$options = $this->_parseOptions();
6 W7 `/ t7 T n8 H e $sql = $this->db->parseSql($sql,$options);# N |2 y3 e) |( Q! \
}elseif(is_array($parse)){ // SQL预处理
0 j7 r& h; ]8 c( y9 ? $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
/ n" n! ], h# O5 j4 m" M+ S $sql = vsprintf($sql,$parse);
- o$ _5 C6 J- O& r k }else{
; {1 h# L. y. J0 ~ $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
4 ? L) w- L7 R4 U, ]8 ]) x/ S }
/ a' p& T& T$ ?' S) h, V/ i: l) D $this->db->setModel($this->name);
6 I9 X9 P. r/ O( R5 b2 ~ return $sql;3 g* V4 g6 p. ^) ~0 g9 d2 B; L
}& } ?% N/ X" |7 _
% E* ^% O( B6 b2 @5 b* c) o总结:1 O: r9 K8 J3 Q
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查2 {0 ~/ i3 r% `, ]! }6 l
不建议直接用$_GET,$_POST
4 X. n& x- n6 f# J[/td][/tr]
( d l W( W( s+ U[/table]+1+ V1 ^! j+ w/ E9 v8 O
! g. A% B" a2 ?4 e' e4 u
5 O. r* q( _ M" ~/ ? |