文档章节

如何防止通过CURL频繁提交请求,后端处理

lock-li
 lock-li
发布于 2016/05/11 16:47
字数 829
阅读 362
收藏 1

今天一个同事,对现有的项目做了一个测试,发现一个很严重的Bug。正常登录进来后,复制完整的cookie值,(我们是用cookie加密进行会话的)
来进行curl模拟其它操作,频繁的插入操作,最终导致表数据量大。

他和说我,对该表数据做一个最大条数限制。对于需求固定的来话,这是一个解决方法。对连续变动变态需求,这些方法往往不行。

这里先不说前端的防护,最终还是要归到后端处理检测。

最终想了个办法,

第一层防护
先给各个模块下的异步请求,做全局限制,只要是ajax异步请求的,才可以访问我们的功能方法。我们的代码结构是按各个功能模块,独自创建异步控制器,如用户模板,可能这样的“UserAjax.class.php”;
这样,我们可以在析构方法里添加一个方法。


public function __construct() {
	parent::__construct ();
	$this->common->isAjax();
}

假设isAjax在common通用方法中:

public function isAjax() {
	if (!isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
		$this->jsonmsg(array('code' => 0, 'msg' => '非法请求'));
	}
}

第二层防护:
对每个请求频率做限制,这个要写一下方法。方法的思路是这样的,对每个请求的IP进行会话保存,存储会话时间戳,再检验时间内规定的请求次数。
下面的方法同样写在common通用方法类中

a、获取IP

public function getIp() {
	if (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
		$ip = getenv('REMOTE_ADDR');
	} elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
		$ip = $_SERVER['REMOTE_ADDR'];
	} elseif (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
		$ip = getenv('HTTP_CLIENT_IP');
	} elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
		$ip = getenv('HTTP_X_FORWARDED_FOR');
	}
	$tmpIp = filter_var($ip, FILTER_VALIDATE_IP);
	$ip = $tmpIp ? $tmpIp : 'unknown';
	return $ip;
}

b、检测时间内请求次数,详情见方法注释

public function checkRequestNumber() {
	//获取IP
	$ip = $this->getIp();
	//请求会话的URI,组合后进行md5加密,因为我们通常一个请求,通过不同的参数调用不同的业务逻辑
	//如ajax_user?op=checkEmail,checkUsername	
	$key = md5($_SERVER['REQUEST_URI'].$_REQUEST['op']);
	
	$errMsg = '提交过于频繁,请稍后再试吧!';
	//IP时间栈数组
	if (!is_array($_SESSION[$ip][$key])) {
		$_SESSION[$ip][$key] = array();
	}
	
	if (isset($_SESSION[$ip][$key][0])) {
		$_SESSION[$ip][$key][] = time();
	
		//session保存时间为60秒,清空session
		$requestFir = time() - $_SESSION[$ip][$key][0];
		if ($requestFir > 60) {
			$_SESSION[$ip][$key] = array();
		}
		
		//两次提交小于1s禁止提交
		$requestSec = time() - $_SESSION[$ip][$key][count($_SESSION[$ip][$key]) - 3];
		if ($requestSec < 1) {
			$this->jsonmsg(array('code' => 0, 'msg' => $errMsg . 1));
		};
		
		//您在10s内已经提交了3请求,禁止提交
		$requestThi = time() - $_SESSION[$ip][$key][count($_SESSION[$ip][$key]) - 3];
		if (isset($_SESSION[$ip][$key][3]) && ($requestThi < 10)) {
			$this->jsonmsg(array('code' => 0, 'msg' => $errMsg . 2));
		}
		
		//您在1分钟期间已经提交了5请求,禁止提交
		$requestFif = time() - $_SESSION[$ip][$key][count($_SESSION[$ip][$key]) - 3];
		if (isset($_SESSION[$ip][$key][5]) && ($requestFif < 60)) {
			$this->jsonmsg(array('code' => 0, 'msg' => $errMsg . 3));
		}
	} else {
		$_SESSION[$ip][$key][] = time();	
	}
}

在基类中调用 checkRequestNumber(),代码如下:

if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
	$common->checkRequestNumber();
}

最后,你也可以对请求频繁的加图片验证码,提示用户操作请求频繁~

 

附上同事请求的CURL模拟小方法:

echo post();

function post($url = 'http://www.test.com/ajax_user', $post_data = '', $timeout = 5){

	$post_data = 'email='.mt_rand(10000,99999999).'@qq.com&op=addemail';
	$cookie = '........';
	$ch = curl_init();
	curl_setopt ($ch, CURLOPT_URL, $url);
	curl_setopt ($ch, CURLOPT_POST, 1);
	curl_setopt ($ch, CURLOPT_COOKIE, $cookie);
	if($post_data != ''){
		curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
	}
	curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
	curl_setopt($ch, CURLOPT_HEADER, false);
	$file_contents = curl_exec($ch);
	curl_close($ch);
	return $file_contents;
}

 

© 著作权归作者所有

共有 人打赏支持
lock-li

lock-li

粉丝 39
博文 73
码字总数 34445
作品 1
松江
CTO(技术副总裁)
加载中

评论(1)

l
lanmanck
你这个有问题,curl每次都没有带cookie,导致每次session重置,你的session判断是无效的,除非带了cookie,或者把ip放到数据库
聚合数据API查询快递数据-短信验证码-企业核名

有位朋友让我给他新开的网站帮忙做几个小功能,如下: 输入快递公司、快递单号,查询出这个快件的所有动态(从哪里出发,到了哪里) 在注册、登录等场景下的手机验证码(要求有一定的防刷策略...

熊babi
2016/08/30
21
0
180730-Spring之RequestBody的使用姿势小结

Spring之RequestBody的使用姿势小结 SpringMVC中处理请求参数有好几种不同的方式,如我们常见的下面几种 根据 对象获取 根据 注解获取url参数 根据 注解获取请求参数 根据Bean的方式获取请求...

小灰灰Blog
07/30
0
0
使用聚合数据API查询快递数据-短信验证码-企业核名

文章来源:http://www.cnblogs.com/annie00/p/5810326.html 有位朋友让我给他新开的网站帮忙做几个小功能,如下: 输入快递公司、快递单号,查询出这个快件的所有动态(从哪里出发,到了哪里...

熊babi
2016/08/30
815
1
如何查看nginx状态?如何统计访问量?

nginx是个什么玩意儿本文不再多说,直奔主题! 1. 如何查看nginx的状态? stub_status 模块介绍 stub_status 模块主要用于查看Nginx的一些状态信息. 本模块默认是不会编译进Nginx的,如果你要...

蜗牛的嘲讽
2016/12/19
0
0
前后端API交互如何保证数据安全性?

前言 前后端分离的开发方式,我们以接口为标准来进行推动,定义好接口,各自开发自己的功能,最后进行联调整合。无论是开发原生的APP还是webapp还是PC端的软件,只要是前后端分离的模式,就避...

尹吉欢
06/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Ubuntu18.04 显卡GF-940MX安装NVIDIA-390.77

解决办法: 下面就给大家一个正确的姿势在Ubuntu上安装Nvidia驱动: (a)首先去N卡官网下载自己显卡对应的驱动:www.geforce.cn/drivers (b)下载后好放在英文路径的目录下,怎么简单怎么来...

AI_SKI
今天
0
0
深夜胡思乱想

魔兽世界 最近魔兽世界出了新版本, 周末两天升到了满级,比之前的版本体验好很多,做任务不用抢怪了,不用组队打怪也是共享拾取的。技能简化了很多,哪个亮按哪个。 运维 服务器 产品 之间的...

Firxiao
今天
0
0
MySQL 8 在 Windows 下安装及使用

MySQL 8 带来了全新的体验,比如支持 NoSQL、JSON 等,拥有比 MySQL 5.7 两倍以上的性能提升。本文讲解如何在 Windows 下安装 MySQL 8,以及基本的 MySQL 用法。 下载 下载地址 https://dev....

waylau
今天
0
0
微信第三方平台 access_token is invalid or not latest

微信第三方开发平台code换session_key说的特别容易,但是我一使用就带来无穷无尽的烦恼,搞了一整天也无济于事. 现在记录一下解决问题的过程,方便后来人参考. 我遇到的这个问题搜索了整个网络也...

自由的开源
今天
2
0
openJDK之sun.misc.Unsafe类CAS底层实现

注:这篇文章参考了https://www.cnblogs.com/snowater/p/8303698.html 1.sun.misc.Unsafe中CAS方法 在sun.misc.Unsafe中CAS方法如下: compareAndSwapObject(java.lang.Object arg0, long a......

汉斯-冯-拉特
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部