文档章节

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

lock-li
 lock-li
发布于 2016/05/11 16:47
字数 829
阅读 453
收藏 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

粉丝 40
博文 73
码字总数 34522
作品 1
松江
CTO(技术副总裁)
私信 提问
加载中

评论(1)

l
lanmanck
你这个有问题,curl每次都没有带cookie,导致每次session重置,你的session判断是无效的,除非带了cookie,或者把ip放到数据库
如何查看nginx状态?如何统计访问量?

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

蜗牛的嘲讽
2016/12/19
0
0
180730-Spring之RequestBody的使用姿势小结

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

小灰灰Blog
07/30
0
0
利用redis缓存解决高并发下后端重复请求措施

最近在进行压力测试的时候发现在高并发下,有些接口很可能因为重复请求导致对数据库操作出来的数据不是你想要的那个样子。比如,用户签到,你只想让用户一天签到一次,为了防止签到多次,你对...

xiaomin0322
04/13
0
0
使用聚合数据API查询快递数据-短信验证码-企业核名

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

熊babi
2016/08/30
865
1
前后端API交互如何保证数据安全性?

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

尹吉欢
06/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Framework7开发H5App如何禁止回退离开首页

将代码放到需要禁止回退的页面即可 主要代码 $(function () {  //防止页面后退  history.pushState(null, null, document.URL);     window.addEventListener('popstate', funct...

老查
3分钟前
0
0
Navicat使用教程(三):使用MySQL日志(第3部分)——慢速日志

下载Navicat for MySQL最新版本 Navicat for MySQL 是一套管理和开发 MySQL 或 MariaDB 的理想解决方案。使用Navicat for MySQL可以同时连接到 MySQL 和 MariaDB。Navicat for MySQL提供了强...

电池盒
8分钟前
0
0
威武 | 有我在,HTTPS更安全!亚洲诚信参展FIT 2019

12月12日-12月13日,备受瞩目的FIT 2019在上海宝华万豪酒店隆重举行。作为FreeBuf互联网安全创新大会(FIT)的长期战略合作伙伴,亚洲诚信受邀参加本次盛会,并与来自全球的行业先锋们聚焦前...

亚洲诚信
11分钟前
0
0
提高 JavaScript 开发效率的高级 VSCode 扩展!

摘要: VScode越来越火了啊。 原文:提高 JavaScript 开发效率的高级 VSCode 扩展! 作者:前端小智 Fundebug经授权转载,版权归原作者所有。 Quokka.js Quokka.js 是一个用于 JavaScript 和...

Fundebug
12分钟前
0
0
docker development note

// on developer clientsudo route -n add -net 172.17.0.0/16 192.168.99.100// on test docker serversudo iptables -A FORWARD -j ACCEPT...

kut
12分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部