下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。
9 g8 g! k0 T8 x! TThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件
3 k+ s5 \7 ~2 k+ k) ?' r根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)+ x' R, |; ^# J: E) s! r$ p' Y; {
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:
* `% s$ p6 A: a$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
4 T1 m4 J* O# y- h6 O3 L( [+ Z8 ]) |2 W+ p; g1 D
或者2 n, j1 w6 S K
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();0 r6 f" s2 _1 d* x& D2 i; B- B
; A8 [% B" [8 C$ Z- u. P 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):, Q8 y3 p+ E7 N5 A- I4 d( y) x
$model->query('select * from user where id=%d and status=%s',$id,$status);
3 P8 T# c$ W# n# l
; S, d: ], }$ |7 m& ^% ^2 v2 C* t; y或者
* _; F% k0 g& x$model->query('select * from user where id=%d and status=%s',array($id,$status));+ J- y2 k; E6 ~, U
7 H; f, g, W1 v# t" L/ w! c 原因:
% l+ S, A9 O+ V8 H3 C! u* eThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤.
# L4 V$ i% f+ H% C4 w7 u/ K原函数:* v( G% X, B/ ~/ Y) r
protected function parseSql($sql,$parse) {6 R2 C+ I }# e
// 分析表达式6 @$ u6 f: U! O) |$ i
if(true === $parse) {
/ ~. `7 a1 O; l! J0 V: u" q& C $options = $this->_parseOptions();
% R3 p& H4 ~4 v- m $sql = $this->db->parseSql($sql,$options);
" U/ P& y: ~) ` }elseif(is_array($parse)){ // SQL预处理7 x, m, q z- c+ q7 m7 C
$sql = vsprintf($sql,$parse);
( }' N3 g$ P" N* P5 U5 { }else{
) a) H& w! M, I $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));$ D* ~2 G$ d) N" z! |$ a
}/ l' i5 v( a& _: F- [/ i6 x' T
$this->db->setModel($this->name);8 D' K# D5 w2 b X% ^
return $sql;! y: l( c, r# i# A% C$ Q
}
: P' f4 H) h9 }8 ~* M- t. X
- U y. m% `3 y/ M3 D/ R验证漏洞(举例):
( H2 i3 L% p. q7 N$ J请求地址:
. ^1 w! \7 a- @" x ehttp://localhost/Main?id=boo” or 1=”1
. Q; O! ~* A9 b# o) @ H) I/ W, N或
p3 x9 n+ j* g1 A6 Z, R2 [http://localhost/Main?id=boo%22%20or%201=%221
* f7 x. s) R1 x7 Oaction代码:# C8 b: A/ R4 @% y
$model=M('Peipeidui');" g. r: K4 o# E4 O6 d) { L9 v9 @
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);) T6 r* J: P6 t" S* @
dump($m);exit;
6 Z/ v0 d- x f. S或者
3 `! \. q; ^4 k. ~$model=M('Peipeidui');: d$ X* h+ U4 n' B
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));! _. L9 Y- y) _! M l0 a& z6 n9 c
dump($m);exit;* @4 Q% o ?& B8 w& m# w
结果:6 F4 x4 r0 G& H! j8 j1 K
表peipeidui所有数据被列出,SQL注入语句起效.
z8 D$ t" Y1 G2 Z8 Y$ [' I解决办法:
7 b. |; ^4 K8 V5 q6 G8 C5 e将parseSql函数修改为:
6 W: D- ?" {7 uprotected function parseSql($sql,$parse) {
2 G; k$ B* z; ]: H7 c/ R+ X. f2 C // 分析表达式
2 A; ?9 O1 x" v% T! j: m8 [ if(true === $parse) {
' `/ s0 C4 P/ q& [: z& A $options = $this->_parseOptions();5 K% `/ ]" \' A" U" \
$sql = $this->db->parseSql($sql,$options);; w4 ~/ M( ^; I, t2 p, ^+ A
}elseif(is_array($parse)){ // SQL预处理, e( L+ b j" S7 w, m
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码 m- N6 Q7 k3 i! L% f
$sql = vsprintf($sql,$parse);
5 X' _: {3 Q# c1 n6 r- ^ }else{
$ E+ `2 z# D5 S* `& t( H% l $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
! @' P8 h/ ~7 r5 D6 k+ v }6 j! f1 j0 q' e2 K
$this->db->setModel($this->name);6 s; o+ ~3 X) F6 Q" a. J' K" y% `
return $sql;! L' L6 c6 T0 Z% w
}
4 h. }/ E0 u* ^7 U% Y7 o) @5 [% Y' m5 X8 j* q
总结:
9 X0 D0 t5 h% M0 y( T不要过分依赖TP的底层SQL过滤,程序员要做好安全检查
2 O3 l, ]7 b. J# V% w7 \! H+ g2 V5 f不建议直接用$_GET,$_POST
1 S( U% l8 H7 b3 k[/td][/tr]
# J* e7 `/ R6 X7 {" E, Y[/table]+1
0 g6 b+ W! W! n( |1 |. v. \- U6 c" W! [% s) ]8 O% l; f4 M
- l/ }( g* f9 N9 I |