下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
% U, A3 `/ \; K: nThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件) z* Z/ A2 N7 J2 Q/ i F8 l: _( {
根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)
. _4 n- ~2 ?5 n7 \使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
7 h1 D% x. N9 ?2 t# a. \$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
* i7 d# q% Q0 M" o0 E) Y) o' X- Q I$ c' o/ v& ]
或者7 L, `1 q( J/ I5 O& o1 Y% s
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
( G/ Z. l- U7 A! {4 K& h
' _; D; [% I2 e( ]: F- w 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):$ X+ b) `% y' L2 N
$model->query('select * from user where id=%d and status=%s',$id,$status);. t: C* s' M G
! F- S2 o' R3 W. [或者
. a+ w0 e. |. b6 J4 d6 m# r. `$model->query('select * from user where id=%d and status=%s',array($id,$status));* n7 m3 E! g- h3 ^' `
* \2 u u/ a) j" K2 N
原因:. Y+ i$ C/ Z$ ^3 H
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.1 m/ B- r% a" z( o$ h
原函数:
3 U* T4 I. n: k* C( Sprotected function parseSql($sql,$parse) {' @7 i& K9 n2 t2 y: Z$ t
// 分析表达式7 ?1 P2 U- Q# ~) P
if(true === $parse) {# q" q* T( t5 t1 R$ Q) n* N6 }
$options = $this->_parseOptions();
8 y. q8 `: K7 j, k $sql = $this->db->parseSql($sql,$options);
8 C2 j9 Y8 A0 S9 M; {1 Z }elseif(is_array($parse)){ // SQL预处理
/ A! i d3 w; [* U2 Y. s4 D $sql = vsprintf($sql,$parse);( M2 ]- {$ F3 N; X) j" S' g& d
}else{
9 N6 _$ z8 D% e( n, X6 o. K $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
; f8 f8 E$ l3 r5 e }: Y: N* `5 l) ~' t
$this->db->setModel($this->name);/ c# M* Z& S8 }# z! P
return $sql;
H9 F8 F2 S+ R" R }, C A7 `4 W6 d# c- X
3 h$ `: l$ a$ ] f) p- `
验证漏洞(举例):
2 a7 J+ @- _! [1 w请求地址:, M4 |( o( d0 N
http://localhost/Main?id=boo” or 1=”19 u) r! X6 t3 ]9 {" R' {
或
9 G" |1 ? D7 s2 B. h/ ^& T& rhttp://localhost/Main?id=boo%22%20or%201=%2213 b3 c* F" C+ U! Q
action代码:" z: a8 ~0 V2 O! F3 ~( J3 E
$model=M('Peipeidui');
+ N% L' Q* U. v; [; N% h8 | $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);
9 G$ r% Z4 }$ ^& X' w dump($m);exit;
0 d' x$ p% H$ @. g" R/ S* }/ |或者
7 P; v; E+ ^6 ~! E$ a$model=M('Peipeidui');
& [; M6 L0 N6 |* h' V $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));
) ~) t/ j% p3 J2 u dump($m);exit;' L5 [0 n( Y+ ?1 C5 m# A/ c' c* `
结果:
* O O5 `1 f( G+ V3 v( M8 m表peipeidui所有数据被列出,SQL注入语句起效.5 x* U' W. @+ |7 a7 n; b
解决办法:
- `/ P. i5 D2 ]4 l将parseSql函数修改为:
3 n1 ^5 [9 X( m& y$ \0 ~3 h# oprotected function parseSql($sql,$parse) {; {. N( Q; @; S9 `( E1 H; t
// 分析表达式
6 i- u3 R6 d+ V2 h if(true === $parse) {* y6 V) c4 {1 I* D5 x& o
$options = $this->_parseOptions();5 `/ f/ w8 p/ O7 | [
$sql = $this->db->parseSql($sql,$options);
! F9 I8 U/ ~/ |8 t" E9 X }elseif(is_array($parse)){ // SQL预处理
: b& w% t" C0 J A5 S7 t" \ $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码
& S R4 c( Y" O1 j" e | $sql = vsprintf($sql,$parse);
6 `9 \( m7 c* P3 Y/ c9 } }else{% _. J; g4 Y$ L7 `0 \% y1 O% m% u
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));- |4 r. N5 @( N- E1 U% |
}* l5 j# Y) M6 E
$this->db->setModel($this->name);
* r: R: l# W8 W return $sql;# g; Y1 E+ F3 G5 j
}6 c3 C5 Q9 m4 }$ c [0 R j
f( f! T& R) w! N& Q t/ M
总结:
# C# J4 F9 s; u6 y* v$ R) @不要过分依赖TP的底层SQL过滤,程序员要做好安全检查0 f: e' q" V5 J
不建议直接用$_GET,$_POST
0 S7 l9 n+ O0 P+ x3 P/ [" ][/td][/tr]6 k( [. \. _( N- ?- D
[/table]+1! ^, e, M7 J0 }; [/ b1 x
; {) W P/ [) d7 e; J; P/ Y5 B3 u% p4 e* J, S% C
|