问题

渗透者在扫站的时候会频繁请求,我们可以做一些策略来封堵这些频繁访问的ip,把ip加入黑名单。

策略

2秒之内访问次数超过100,加入黑名单。

实现思路

  1. 初次访问把访问Ip作为键,访问ip,时间,次数(初始值为1)封装为一个对象作为value,放入map。
  2. 开启定时器,定时器每秒执行一次,在定时器里面循环map,2秒之内访问次数超过100的ip加入黑名单数组,同时清除加入黑名单ip对应的map key和value.
  3. 在代理程序之前,判断请求过来的ip是否在黑名单,如果在,就拒绝访问。

核心代码

/**
www.qingmiaokeji.cn
* ip 频繁访问限制策略
* 2秒之内访问次数超过100,加入黑名单。
* 可能存在并发问题
* @constructor
*/
function IPPolicy () {
this.cache = {};
this.blackIpList=[];
var $this = this;
setInterval (function () {
var nowTime = new Date().getTime();
for(ip in $this.cache){
var item = $this.cache[ip];
var timeDif = nowTime - item.visitTime;
if(timeDif<2000 && item.count>100 ){
$this.blackIpList.push(ip)
delete $this.cache[ip];
}else{
item.count = 0;
}
}
},1000)
}
IPPolicy.prototype.addVisitIp = function (ip) {
if(this.cache[ip]){
this.cache[ip].count = this.cache[ip].count+1;
this.cache[ip].visitTime =new Date().getTime();
}else{
this.cache[ip] ={"ip":ip,"count":1,"visitTime":new Date().getTime()}
}
}

完整代码

var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('./node_modules/http-proxy'),
fs = require("fs"); var welcome = [
'# # ##### ##### ##### ##### ##### #### # # # #',
'# # # # # # # # # # # # # # # # ',
'###### # # # # ##### # # # # # # ## # ',
'# # # # ##### ##### ##### # # ## # ',
'# # # # # # # # # # # # # ',
'# # # # # # # # #### # # # '
].join('\n'); Date.prototype.Format = function(fmt) { //author: meizz
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
} String.prototype.startWith=function(str){
var reg=new RegExp("^"+str);
return reg.test(this);
} // 非法字符
var re = /php|exe|cmd|shell|select|union|delete|update|truncate|insert|eval|function/;
/** 这里配置转发
*/
var proxyPassConfig = {
"/test": 'http://127.0.0.1:8080/hello',
"/": "http://www.qingmiaokeji.cn/"
} /**
* ip 频繁访问限制策略
* 2秒之内访问次数超过100,加入黑名单。
* 可能存在并发问题
* @constructor
*/
function IPPolicy () {
this.cache = {};
this.blackIpList=[];
var $this = this;
setInterval (function () {
var nowTime = new Date().getTime();
for(ip in $this.cache){
var item = $this.cache[ip];
var timeDif = nowTime - item.visitTime;
if(timeDif<2000 && item.count>100 ){
$this.blackIpList.push(ip)
delete $this.cache[ip];
}else{
item.count = 0;
}
}
},1000)
}
IPPolicy.prototype.addVisitIp = function (ip) {
if(this.cache[ip]){
this.cache[ip].count = this.cache[ip].count+1;
this.cache[ip].visitTime =new Date().getTime();
}else{
this.cache[ip] ={"ip":ip,"count":1,"visitTime":new Date().getTime()}
}
} var iPPolicy = new IPPolicy(); var logRootPath ="d:/httpproxy/"; console.log(welcome.rainbow.bold); //
// Basic Http Proxy Server
//
var proxy = httpProxy.createProxyServer({});
var server = http.createServer(function (req, res) {
appendLog(req) var ip = getClientIp(req)
if(iPPolicy.blackIpList.indexOf(ip)>=0){
console.log("ip在黑名单");
backIpHandler(res)
return
}
iPPolicy.addVisitIp(ip); var postData = "";
req.addListener('end', function(){
//数据接收完毕
console.log(postData);
if(!isValid(postData)){//post请求非法参数
invalidHandler(res)
}
});
req.addListener('data', function(postDataStream){
postData += postDataStream
}); var patternUrl = urlHandler(req.url);
console.log("patternUrl:" + patternUrl); if (patternUrl) {
var result = isValid(req.url)
//验证http头部是否非法
for(key in req.headers){
result = result&& isValid(req.headers[key])
}
if (result) {
proxy.web(req, res, {target: patternUrl});
} else {
invalidHandler(res)
}
} else {
noPattern(res);
}
}); //代理异常捕获
proxy.on('error', function (err, req, res) {
console.error(err)
try{
res.writeHead(500, {
'Content-Type': 'text/plain'
}); res.end('Something went wrong.');
}catch (e) {
console.error(err)
} }); /**
* 验证非法参数
* @param value
* @returns {boolean} 非法返回False
*/
function isValid(value) {
return re.test(value.toLowerCase()) ? false : true;
} /**
* 请求转发
* @param url
* @returns {*}
*/
function urlHandler(url) {
if("/" == url)
return proxyPassConfig["/"]; for(patternUrl in proxyPassConfig ){
if(url.startWith(patternUrl)){
return proxyPassConfig[patternUrl]
} }
return proxyPassConfig[tempUrl];
}
//非法请求
function invalidHandler(res) {
res.writeHead(400, {'Content-Type': 'text/plain'});
res.write('Bad Request ');
res.end();
} function backIpHandler(res) {
res.writeHead(500, {'Content-Type': 'text/plain',"charset":"utf-9"});
res.write('ip frequent access ');
res.end();
} //匹配不到
function noPattern(res) {
res.writeHead(404, {'Content-Type': 'text/plain'});
res.write('not found');
res.end();
} //获取访问id
function getClientIp(req){
return req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress;
} //当天日志名称生成
function getCurrentDayFile(){
return logRootPath+"access_"+(new Date()).Format("yyyy-MM-dd")+".log";
} //访问日志
function appendLog(req) {
console.log("request url:" + req.url);
var logData = (new Date()).Format("yyyy-MM-dd hh:mm:ss")+" "+getClientIp(req)+" "+req.method+ " "+req.url+"\n";
fs.exists(logRootPath,function(exists){
if(!exists){
fs.mkdirSync(logRootPath)
}
fs.appendFile(getCurrentDayFile(),logData,'utf8',function(err){
if(err)
{
console.log(err);
}
});
})
} console.log("listening on port 80".green.bold)
server.listen(80);

不足之处

  • 对map操作可能不是线程安全?
  • 定时器循环map元素需要时间,2秒时间间隔上可能不是很准确。

完善扩展

  • 可用redis的过期缓存机制来实现频繁访问的缓存功能。

大概先这么多。。。

【nodejs代理服务器四】代理服务器增加频繁访问的ip加入黑名单的更多相关文章

  1. linux安全篇:禁止频繁访问的ip访问nginx

    实验环境 版本:redhat6.5ip:172.16.1.100,172.16.10软件:nginx 172.16.1.10部署nginx [root@localhost tools]# lsngin ...

  2. Oracle数据库IP访问限制(IP白名单黑名单)

    1.编辑sqlnet.ora 内容为: #允许访问的IP(白名单) TCP.INVITED_NODES=(127.0.0.1,192.168.56.109,ip2,ip3,..,..本地IP..)若使 ...

  3. shiro之redis频繁访问问题

    目前安全框架shiro使用较为广泛,其功能也比较强大.为了分布式session共享,通常的做法是将session存储在redis中,实现多个节点获取同一个session.此实现可以实现session共 ...

  4. PHP禁止同一IP频繁访问以防止网站被防攻击或采集的代码

    PHP禁止同一IP频繁访问以防止网站被防攻击或采集的代码 <?php /* *通过禁止IP频繁访问防止网站被防攻击代码*design by www.scutephp.com*/header('C ...

  5. .Net频繁访问数据库的优化探究(一)

    知识点:DataTable.Linq.lamda表达式.Cache 场景:查询部门的所有员工和管理员,并分配相应的权限 实现过程一般为:查询部门,遍历部门(查询员工.分配权限.查询管理员.分配权限) ...

  6. 域名访问和ip访问区别

    域名访问和ip访问区别 ip访问对应某一台确定的服务器: 域名访问相当于在ip访问的基础上,做了一个反向代理的中间功能.例如:百度,很多人会同时使用,如果使用的是同一台服务器的话,服务器估计会扛不住, ...

  7. 转载:通过监控Nginx日志来实时屏蔽高频恶意访问的IP

    通过监控Nginx日志来实时屏蔽高频恶意访问的IP   目前在我的VPS上主要通过两种方式来限制ip的访问次数. 通过Nginx的limit_req配置来限制同一ip在一分钟内的访问次数 通过Ngin ...

  8. 获取客户端访问真实 IP

    转载自:https://www.qikqiak.com/post/get-client-realip/ 通常,当集群内的客户端连接到服务的时候,是支持服务的 Pod 可以获取到客户端的 IP 地址的, ...

  9. Nginx禁止ip访问或IP网段访问方法

    Nginx禁止ip访问可以防止指定IP访问我们的网站,本例子可以实现是防止单IP访问或IP网段访问了,非常的有用我们一起来看看吧. 常用的linux做法 iptables参考规则  代码如下 复制代码 ...

随机推荐

  1. Qt编写气体安全管理系统20-控制器管理

    一.前言 控制器管理,主要就是对控制器进行添加删除和修改,其中包括编号.端口名称.控制器名称.控制器地址.控制器型号.探测器数量这几个字段,端口名称表示当前控制器所属哪个端口,一个系统中可以有好多个端 ...

  2. Linux记录-limits.conf 配置

    limits.conf 文件实际是 Linux PAM(插入式认证模块,Pluggable Authentication Modules)中 pam_limits.so 的配置文件,而且只针对于单个会 ...

  3. Python和Pygame游戏开发 pdf

    Python和Pygame游戏开发 目录 第1章 安装Python和Pygame 11.1 预备知识 11.2 下载和安装Python 11.3 Windows下的安装说明 11.4 Mac OS X ...

  4. shell脚本通过子网掩码计算出掩码位数

    子网掩码格式为255.255.255.0可以通过以下脚本计算掩码位数 #!/bin/sh #maskdigits.sh mask maskdigits () { a=$(echo "$1&q ...

  5. Linux chomd命令

    file 语法为: chmod abc file 其中a,b,c各为一个数字,分别表示User.Group.及Other的权限. r=4,w=2,x=1 若要rwx属性则4+2+1=7: 若要rw-属 ...

  6. [bzoj4240]有趣的家庭菜园_树状数组

    有趣的家庭菜园 题目链接:https://lydsy.com/JudgeOnline/problem.php?id=4240 数据范围:略. 题解: 第一步比较简单,只需要排序之后,每个数不是在左边就 ...

  7. ALT+J 多行编辑

    很方便!!!

  8. Amazon SQS 消息队列服务

    Amazon sqs是亚马逊提供的线上消息队列服务, 可以实现应用程序解耦,以及可靠性保证. sqs提供了两种消息队列, 一种是标准消息队列, 一种是先进先出队列(FIFO), 其区别是FIFO是严格 ...

  9. NOIP2017[提高组] 宝藏 题解

    解析 我们观察范围可以发现n非常的小,(一般来说不是搜索就是状压dp)所以说对于这题我们可以用记忆化搜索或者dp,我们发现起点不同那么最终答案也就不同,也就是说答案是跟起点有关的,于是我们便可以想到去 ...

  10. ArcGIS Server Identify结果属性 AliasName

    最近做地图服务相关工作,一般在数据库中,字段名有好多限制,而实际工作中,需要显示的经常有一些较长的字段或者包含单位等特殊符号. 为了方便属性的操作,将属性字段名改为英文,AliasName中保存了属性 ...