问题

渗透者在扫站的时候会频繁请求,我们可以做一些策略来封堵这些频繁访问的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. 《楞严经四种清净明诲》 (转自学佛网:http://www.xuefo.net/nr/article56/559965.html)

    <楞严经四种清净明诲> 佛告阿难:“汝常闻我毗奈耶中,宣说修行三决定义.所谓摄心为戒,因戒生定,因定发慧,是则名为三无漏学. “阿难,云何摄心,我名为戒? “若诸世界六道众生其心不淫,则不 ...

  2. docker容器中解决出现:^H^H^H^H

    docker容器中解决出现:^H^H^H^H 环境:docker容器是debain系统 解决: 把stty erase ^H 添加到.bash_profile中 vim /etc/profile st ...

  3. 正则表达式\s空格,\d数字,量词+*?测试

    之前的博文中: 有正则表达式的\b.i.\g,本文再测试了空格数字和量词的匹配.这篇只测试匹配,不替换或其他处理.\s空格:测试实际写空格也能识别,但是不利于看出空了几个空格,可以用\s代表空格.\d ...

  4. 【Leetcode_easy】1071. Greatest Common Divisor of Strings

    problem 1071. Greatest Common Divisor of Strings solution class Solution { public: string gcdOfStrin ...

  5. express获取http参数

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

  6. 【GStreamer开发】GStreamer基础教程02——GStreamer概念

    上一个教程演示了如何自动生成一个pipeline.这次我们打算用一个个element来手动搭建一个pipeline.我们这个教程会演示: 1. 什么是GStreamer的element以及如何建立一个 ...

  7. 记录一下vue slot

    使用步骤: 1.在组件(panda)当中建立一个slot,定义好name.(<slot name='myname'></slot>)    2.引用组件的时候如果需要补充内容, ...

  8. PHP判断上传图片的类型

    PHP判断上传图片的类型用getimagesize来判断上传图片的类型比$_FILES函数的type更可靠 同一个文件,使用不同的浏览器php返回的type类型是不一样的,由浏览器提供type类型的话 ...

  9. idea使用maven+Tomcat

    1.创建maven项目,并使用webapp骨架,并修改pom.xml文件 <build> <finalName>myWebApp</finalName> <! ...

  10. str.format() 格式化数字的多种方法

    Python2.6 开始,新增了一种格式化字符串的函数 str.format(),它增强了字符串格式化的功能. 基本语法是通过 {} 和 : 来代替以前的 % . format 函数可以接受不限个参数 ...