下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
" }8 W6 c" ?, W( O5 a, oThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
. R7 y3 E* n. x b0 G根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
. k, L O# B0 Z, \使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:$ b1 S, v; p5 Q: @+ c
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();. f/ D' b, \7 i
5 g- t; A- Z. D) u! U$ z 或者$ ~, y3 u" S& s$ o" M
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();, a3 c4 U3 @* `$ P$ v9 K( ^( E
# Q$ O, i& `. U. [& ^4 f4 ~/ d6 S
但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):; ]" K9 a* O: \
$model->query('select * from user where id=%d and status=%s',$id,$status); G5 F) n; }5 E) Z. O4 \
5 I# y1 W5 S5 d. y3 u4 l7 V; g: B
或者
! ]! H: v, V V' |' X7 U$model->query('select * from user where id=%d and status=%s',array($id,$status));. ~: D; C# ?; V! K. l! ^
/ O* y8 I7 \& B# b- F* z
原因:) D2 H; X! h$ O+ u% k# j1 c
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
0 I/ |4 ]' s; L8 U2 I2 p原函数:
0 _0 q% T! M) c# i! W+ E0 V8 V7 Sprotected function parseSql($sql,$parse) {) e2 Z% b8 @* g. ~5 K7 S% `. F7 y
// 分析表达式, h/ c2 G7 Q5 e
if(true === $parse) {
# b5 O2 A9 O( o" e$ ^ $options = $this->_parseOptions();
! U" L4 q7 [8 C/ C# P Y/ F $sql = $this->db->parseSql($sql,$options);$ T) b( m. `% s$ A+ [% a
}elseif(is_array($parse)){ // SQL预处理
2 G0 T1 r4 P4 B$ m! T $sql = vsprintf($sql,$parse);9 B8 e5 f( o |) C2 a0 }$ C
}else{
0 `& u w9 G% G$ l, [ $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));( T% F% }6 V& w8 E2 ]( x
}
; o, a6 Z& c$ S! X; A" o $this->db->setModel($this->name);
# f1 A0 d7 U' W. W# H return $sql;2 C3 Z+ n. \( j; l; p. B" N& T! P1 _
}
5 v, M2 m5 G& w" d: l3 X( _* C. l( H8 t% c1 K& g+ Z4 b; g8 y
验证漏洞(举例):2 G. l# K8 G! h8 i6 m8 z, |, a
请求地址:
5 k- }5 h! N# t- khttp://localhost/Main?id=boo” or 1=”1
* p+ I0 {& e* I' p( k或
& x. o, p8 ^4 ]2 v8 yhttp://localhost/Main?id=boo%22%20or%201=%221' H) ^5 u8 H- J" m/ G) Z9 ]
action代码:- W8 A% r/ V( V- X% O0 \
$model=M('Peipeidui');# `4 B9 ?+ x: J1 j7 k/ C# z
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);0 u6 w1 L6 |. G
dump($m);exit;( G) g( ^+ U; ?
或者- X* _2 \' ^# ]- s( N
$model=M('Peipeidui');+ g9 t! @: I0 j
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
8 j. m" e, j5 ~6 \6 i) @! x$ S1 w: D dump($m);exit;
# \5 z6 q+ L( ?结果:
8 s9 W4 g; Y& b+ n表peipeidui所有数据被列出,SQL注入语句起效./ O) [/ c5 y. o
解决办法:
% t" i; d6 T* v ]. P1 Y1 ^将parseSql函数修改为:
! q+ _4 g# F9 p1 b! j- e* Z1 i6 Tprotected function parseSql($sql,$parse) {
- S" p1 u9 }8 \ // 分析表达式, N+ g. n# Q0 u2 A4 C7 o
if(true === $parse) {
3 Z, `1 X& z% Y3 U8 R $options = $this->_parseOptions();( \) S0 O9 O2 Y8 g" A; d
$sql = $this->db->parseSql($sql,$options);
0 f' M8 [4 s8 {- t1 y: a; a8 y9 _, D }elseif(is_array($parse)){ // SQL预处理
+ m5 b6 _+ ~, F& J9 l $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
% `( k% a8 g( a {$ P# y $sql = vsprintf($sql,$parse);( m* \, {; R* b* G# N8 @" ^% ~ y; x- P
}else{
. n8 `; f: b" w' r0 { $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));7 z7 W: K4 n* e( H7 h! ]
}
. l- k. M9 {5 i6 l2 a# r, | $this->db->setModel($this->name); M' i8 V6 v4 S) V9 O4 ]
return $sql;
9 P l9 |. F# I1 y }: O( P/ j7 u: t9 _
0 {: ^2 ]( n9 F
总结:4 R, R7 t0 w1 `; b6 ~6 s2 S
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
+ d+ U6 N0 {1 h, Q2 e0 \不建议直接用$_GET,$_POST9 Z4 E( _9 }2 F' }6 c8 s9 N
[/td][/tr]7 _1 d- _2 R) k- t% K3 x6 z- R
[/table]+1
' @. l4 X7 E6 `* C) x- R& z1 F6 p+ n- k7 C; _
- }: ]& Z- w. y' r5 u0 A' i' T
|