问题

渗透者在扫站的时候会频繁请求,我们可以做一些策略来封堵这些频繁访问的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. html5 导航栏切换效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. express获取http参数

    express获取参数有三种方法:官网介绍如下 Checks route params (req.params), ex: /user/:id Checks query string params ( ...

  3. Pycharm use GUP server

    1.配置远程服务器信息 Tools——Deployment——Configuration 然后,点击加号Add一个远程服务信息. 我这里命名为server1:Type选择SFTP:Host即ip地址, ...

  4. python 最麻烦的时间有药了

    https://www.cnblogs.com/sunshineyang/p/6818834.html 一:经常使用的时间方法 1.得到当前时间 使用time模块,首先得到当前的时间戳 In [42] ...

  5. javascrtpt DOM操作

    DOM DOM:(document object mode)文档对象模型.DOM为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构. 目的就是为了能让js操作html元素而制定的一个规范 DO ...

  6. NMF包的安装

    win10 操作系统,R3.4版本 NMF包的下载 source("https://bioconductor.org/biocLite.R") biocLite("Bio ...

  7. [PDF] - 获取 RadioButtonList 控件值的方法

    背景 目标是通过 iTextSharp 读取 PDF 模板,填充内容后以生成新 PDF 文件.利用 福昕PDF编辑器个人版 可以获取到 RadioButtonList 的组名,但是获取不到每一个 Ra ...

  8. java实现根据特定密钥对字符串进行加解密功能

    在项目中我们经常遇到这样的场景,我们避免重要资源泄露需要将一些信息按照特定的方式(密钥)进行加密保存,然后在使用的时候再按照特定的方式(密钥)进行解密读取,以保证信息的相对安全.那么如何对信息进行加解 ...

  9. Python字典dict的基本使用

    可以将字典看作是特殊的列表,将下标0.1.2,表示成name,age,job. 程序列出了基本的增删改查,其余方法自行测试. 1.程序测试 #!/usr/bin/python # -*- coding ...

  10. Ubuntu的apt命令详解()deepin linux是在Ubuntu基础上开发的

    apt-cache和apt-get是apt包的管理工具,他们根据/etc/apt/sources.list里的软件源地址列表搜索目标软件.并通过维护本地软件包列表来安装和卸载软件. 查看本机是否安装软 ...