【nodejsプロキシ4】プロキシサーバーが頻繁にアクセスするipを増やしてブラックリストに加える

7826 ワード

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