下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。% s6 s. {/ i0 E0 d
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件+ B3 B9 @2 {3 j" i/ N
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html) C d) T/ M9 s
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
; J: ?. E4 q) f: A0 o$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();/ W! f, {. @4 L2 ~
: f( V8 C/ k* d4 F; q 或者
/ v$ z3 q6 r- A$ |2 I) s3 E$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
9 s0 d, f! g% o
2 T' {4 G/ I7 L. @( p 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):
! V2 _3 Z! ?6 F4 G$model->query('select * from user where id=%d and status=%s',$id,$status);. M/ r- t8 a* S* S' y0 t/ P y
~. A9 M [ a! \( `7 W或者( N! Y9 a; u) F/ Y( ^/ H
$model->query('select * from user where id=%d and status=%s',array($id,$status));8 a/ E. t0 y) n" X R3 \$ B5 W! U" W
; D7 n! d% h' N3 b3 y 原因:
) W4 w* S* p7 A/ Y' h; e5 yThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.2 K1 R/ \- i1 j; K% F! B6 [
原函数:
) B7 q0 ?' b6 V; T/ b# O Xprotected function parseSql($sql,$parse) {
" }6 H, L* ]6 d3 g. E$ Z3 U: q // 分析表达式
1 k y6 o, l; O9 k ]0 O' U9 Z if(true === $parse) {
3 @5 G4 T6 n7 P% ~$ B $options = $this->_parseOptions();, J) c0 x9 y+ r$ n t8 r. N: c
$sql = $this->db->parseSql($sql,$options);- R/ k, A5 }& r+ H7 }( R
}elseif(is_array($parse)){ // SQL预处理4 u1 U/ V7 }+ N# Y3 K+ @/ U
$sql = vsprintf($sql,$parse);
) a4 e4 i: H- W3 h3 d }else{& C; J- q: E( v* Z$ I9 U
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
. O, c: E6 G$ {$ ^. n }6 Z: P) V0 b$ F8 [# q* ^# M
$this->db->setModel($this->name);1 O1 |; ]- z [+ z2 O
return $sql;
3 z3 q" Z# X! m' H+ }6 p }
" S2 d6 t% Y% |& @: ~6 N& K% T
3 C0 x1 Y# { ]' i2 h( k, }验证漏洞(举例):
3 E% F; L8 L" B3 ^2 P$ `1 z+ n* g请求地址:$ `* n6 s+ u. e J
http://localhost/Main?id=boo” or 1=”1
2 {! x5 S% h1 U0 Y. I4 E) ?& h+ |- e3 }6 |或
& \7 D2 a. @/ nhttp://localhost/Main?id=boo%22%20or%201=%221) E, Z6 R0 A$ H' a7 D ^
action代码:6 C9 [5 d: Z. v2 h6 [, Q
$model=M('Peipeidui');: b4 }8 P7 e% c' U, w+ U
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);. A6 Y4 ^ p3 Q
dump($m);exit;
+ R& Y0 l s& L或者
9 {3 ]% ^7 B6 K. d. l* k$model=M('Peipeidui');6 l; e; Y3 ], D' K4 V9 N
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));& t s1 [) y. y: W
dump($m);exit;
* O, F/ a$ x3 H2 `结果:
0 g+ G* v" U0 L表peipeidui所有数据被列出,SQL注入语句起效.
( Z E+ I& ?+ j解决办法:
$ S0 _! J5 P% U# s& m将parseSql函数修改为:8 _+ k7 g8 Q7 K8 a6 K2 B) |
protected function parseSql($sql,$parse) {
. n, J9 Y( B* `1 a! r // 分析表达式
* M2 _1 U0 Y6 h3 \( J j1 b1 i if(true === $parse) {
( N8 H0 L' V* ^- i0 M3 i $options = $this->_parseOptions();
& f- Y/ ?7 U: m5 _" z1 I. B$ s4 r $sql = $this->db->parseSql($sql,$options);
' Q* s/ w: j, y! C7 T0 g }elseif(is_array($parse)){ // SQL预处理% u8 G- H. F# V1 A
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
- q( G. T( z) A' l0 m$ H4 } $sql = vsprintf($sql,$parse);
7 f a- r5 J% }% J! r$ G0 H }else{
; G( ^9 f4 ]+ X0 |3 H( {# x $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));% t6 Y+ K1 I; z( A$ a7 z+ ^# k
}5 `; `- m+ [9 y, g" M' G) O
$this->db->setModel($this->name);
5 z& @1 e0 R- s, a! }1 _" ?4 \ return $sql;
. ` e7 b, ^- n }
8 n. z( m: I: R4 `- _3 Z. b: S2 T
2 F6 J p% b0 M0 Q/ l! g O1 G总结:4 I, f% S! ^7 ]5 {
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
4 h+ p' p7 g J# E不建议直接用$_GET,$_POST
5 n7 ] w! i1 @7 j! h d[/td][/tr]6 E, O7 H" X( i
[/table]+13 ` ]+ _2 I, n; e- L2 V6 W2 w
4 B1 \+ `7 n: K0 l* O# N+ A
9 h+ s# H- G- `0 ~1 T6 y
|