【nodejsプロキシ4】プロキシサーバーが頻繁にアクセスするipを増やしてブラックリストに加える
7826 ワード
問題
侵入者はスイープステーションで頻繁に要求します.頻繁にアクセスするこれらのipをブロックするために、いくつかのポリシーを実行して、ブラックリストにipを追加します.
策略
2秒以内に訪問回数が100を超えてブラックリストに入ります.
構想を実現する初めてのアクセスは、アクセスIpをキーとして、ipにアクセスし、時間、回数(初期値は1)を1つのオブジェクトにラッピングし、mapに入れる. はタイマーをオンにして、タイマーは毎秒一回実行して、タイマーの中で循環mapをして、2秒以内にアクセス回数が100を超えるipはブラックリストの配列に参加して、ブラックリストipに対応するmap keyとvalueをクリアします. は、プロキシの前に、要求されたipがブラックリストにあるかどうかを判断し、不在の場合はアクセスを拒否する. ハコアコードのmap操作はスレッドの安全ではないかもしれませんか? タイマーサイクルmap要素は時間がかかります.2秒間隔は正確ではないかもしれません.完全拡張 は、頻繁にアクセスするキャッシュ機能を実現するために、redisの期限切れキャッシュメカニズムを利用することができる. まずこれぐらいです.
侵入者はスイープステーションで頻繁に要求します.頻繁にアクセスするこれらのipをブロックするために、いくつかのポリシーを実行して、ブラックリストにipを追加します.
策略
2秒以内に訪問回数が100を超えてブラックリストに入ります.
構想を実現する
/**
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('
');
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+"
";
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);
足りないところ