前言
之前有人请教我怎么限制typecho邮件通知里的找回密码请求,我看了看这好像是个挺严重的问题,如果没有限制请求频率,可能一些不怀好意的人会一直恶意请求,导致发送邮箱账号被封号,或者标记为垃圾邮箱,所以我研究了一会儿,想了比较多的方案,比如:
- 前端js拦截(设置多少秒解除提交按键的禁用属性)但是因为typecho插件的性质组件初始化的顺序不同,可能js提前加载无法绑定到按钮,而且每次进入都禁用一些时间,非常影响体验,所以pass掉了。
- 设置cookie临时存储提交的时间,找通过js拦截请求的发起,很明显这个实现比第一个体验上好了一点,但是这个办法有漏洞清除掉cookie就又可以请求,而且实现起来有点难度,因此也pass了。
- 最后我想到了一个好办法,比上面两个实现起来容易且能稳定运行,通过查询数据库验证请求,我最后选择了这种方法,方法已经更新到了插件和我的定制版后台里,下载最新版本安装后,取消插件里
XGComment/Action.php
大概307-309行的代码注释即可开启功能,加注释防止有人安装到官方的Typecho,请求数据库查不到表单报错。
教程
1.打开数据库找了typecho_users表,点击结构添加一列
- 名称
rtime
- 类型
int
- 长度
10
- 允许为空 默认填充 0
用来存储提交时写入数据库的时间戳。
2.打开插件的 Plugin.php
文件
在 找回密码过期时间 的下一行插入以下代码
// 找回密码请求间隔时间
$public_rtime = new Typecho_Widget_Helper_Form_Element_Text('public_rtime', NULL, '180', _t('请求间隔时间'), _t('防止恶意请求,开启需要定制版typecho且删除Action.php中相关的代码注释,此处定义找回密码请求间隔时间,单位为秒'));
$form->addInput($public_rtime);
3.打开插件的 Action.php
文件
找到 doForget()
方法,这是验证并创建重置密码链接发送邮件的方法。
只要在验证处添加一个时间戳验证,设置好时间间隔,这样每次点击提交找回密码请求后,方法就会查询数据库比较时间
将 doForget()
方法的以下片段替换成下面的片段
// 查询用户数据
$user = $this->db->fetchRow($this->select()->where('mail = ?', $this->request->mail));
$now = time();
$retime = $user['rtime'];
// 没有用户
if ( !$user ) {
// 输出错误
$this->widget('Widget_Notice')->set(_t('邮箱地址错误, 请核对后重新输入'), 'error');
// 返回上一页
$this->response->goBack();
}
if ( $now<=$retime ) {
// 输出错误
$this->widget('Widget_Notice')->set(_t($this->request->mail.'您已申请过重置密码请求,请稍后重试!'), 'error');
// 返回上一页
$this->response->goBack();
}
$addtime = $this->_plugin->public_rtime ? $this->_plugin->public_rtime : 180;
$setime = $now + $addtime;
$this->update(array('rtime' => $setime), $this->db->sql()->where('mail = ?', $this->request->mail));
评论