介绍
最近对于WordPress的博客框架爆破事件层出不穷,必须加个验证码防止爆破。反正我是没搞懂用WordPress的爆破来爆破Typecho是什么心态。
准备工作
- 谷歌验证码API
- 中国境内使用reCaptcha的镜像
处理方法
在var/Widget/Login.php
中找到action方法,对比修改添加。
/**
* 初始化函数
*
* @access public
* @return void
*/
public function action()
{
// protect
$this->security->protect();
/** 如果已经登录 */
if ($this->user->hasLogin()) {
/** 直接返回 */
$this->response->redirect($this->options->index);
}
/** 初始化验证类 */
$validator = new Typecho_Validate();
$validator->addRule('name', 'required', _t('请输入用户名'));
$validator->addRule('password', 'required', _t('请输入密码'));
$validator->addRule('g-recaptcha-response', 'required', _t('请输入验证码')); //加入
/** 截获验证异常 */
if ($error = $validator->run($this->request->from('name', 'password', 'g-recaptcha-response'))) {
Typecho_Cookie::set('__typecho_remember_name', $this->request->name);
/** 设置提示信息 */
$this->widget('Widget_Notice')->set($error);
$this->response->goBack();
}
/** 开始验证用户 **/
/** Google reCaptcha v2 */
//加入
$post_data = [
'secret' => '你的Google API密钥',
'response' => $_POST["g-recaptcha-response"]
];
$recaptcha_json_result = $this->send_post('https://www.google.com/recaptcha/api/siteverify', $post_data);
$recaptcha_result = json_decode($recaptcha_json_result, true);
if(!$recaptcha_result['success']){
/** 设置提示信息 */
$this->widget('Widget_Notice')->set(_t('请输入验证码'));
$this->response->goBack();
}
$valid = $this->user->login($this->request->name, $this->request->password,
false, 1 == $this->request->remember ? $this->options->time + $this->options->timezone + 30*24*3600 : 0);
/** 比对密码 */
if (!$valid) {
/** 防止穷举,休眠3秒 */
sleep(3);
$this->pluginHandle()->loginFail($this->user, $this->request->name,
$this->request->password, 1 == $this->request->remember);
Typecho_Cookie::set('__typecho_remember_name', $this->request->name);
$this->widget('Widget_Notice')->set(_t('用户名或密码无效'), 'error');
$this->response->goBack('?referer=' . urlencode($this->request->referer));
}
$this->pluginHandle()->loginSucceed($this->user, $this->request->name,
$this->request->password, 1 == $this->request->remember);
/** 跳转验证后地址 */
if (NULL != $this->request->referer) {
$this->response->redirect($this->request->referer);
} else if (!$this->user->pass('contributor', true)) {
/** 不允许普通用户直接跳转后台 */
$this->response->redirect($this->options->profileUrl);
} else {
$this->response->redirect($this->options->adminUrl);
}
}
文件末尾添加一个send_post的方法
private function send_post($url, $post_data)
{
$postdata = http_build_query($post_data);
$options = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type:application/x-www-form-urlencoded',
'content' => $postdata,
'timeout' => 20 // 超时时间(单位:s)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
return $result;
}
对于前台的页面,打开admin/Login.php
。
在密码的p标签下另起一行插入
<p>
<label for="password" class="sr-only"><?php _e('密码'); ?></label>
<input type="password" id="password" name="password" class="text-l w-100" placeholder="<?php _e('密码'); ?>" />
</p>
<!-- 插入 -->
<div class="g-recaptcha" data-sitekey="6LfU4dIUAAAAADFaigTFmhuYUYXvkMYC5t3HnAvr"></div>
<p class="submit">
<button type="submit" class="btn btn-l w-100 primary"><?php _e('登录'); ?></button>
<input type="hidden" name="referer" value="<?php echo htmlspecialchars($request->get('referer')); ?>" />
</p>
在底部footer前插入script标签
<script>
$(document).ready(function () {
$('#name').focus();
});
</script>
<!-- 插入 -->
<script src="https://www.recaptcha.net/recaptcha/api.js" async defer></script>
<?php
include 'footer.php';
?>