2014-10-10 4 views
7

DDoS 공격을 당하면 node.js 애플리케이션의 손상을 최소화하는 방법을 생각하려고합니다. IP 당 요청을 제한하고 싶습니다. 초당 많은 요청에 모든 IP 주소를 제한하고 싶습니다. 예 : 3 초마다 10 개의 요청을 초과 할 수있는 IP 주소가 없습니다. 지금까지이 함께 올라와있다Node.JS에서 IP 당 요청량을 제한하는 방법은 무엇입니까?

:

http.createServer(req, res, function() { 
    if(req.connection.remoteAddress ??????) { 
     block ip for 15 mins 
     } 
} 
+1

DOS를 방어 할 수는 있지만 DISTRIBUTEDdos 공격에 대해서는 방어 할 수 없습니다! – loveNoHate

+1

Nginx 등을 Node.js 애플리케이션 서버 앞에 놓는 것이 좋습니다. 보다 효율적으로 작동하는 더 많은 도구가 있고 응용 프로그램 서버가 최선을 다해 응용 프로그램을 실행하게 할 수 있습니다. – Brad

답변

4

앱 서버 수준에서이 자신을 구축하려는 경우, 새 요청이 도착하면, 다시 검색 할 수 있도록 특정 IP 주소에서 각각 최근의 접속을 기록하는 데이터 구조를 구축해야합니다 역사를 통해 너무 많은 요청을했는지 확인하십시오. 그렇다면 추가 데이터를 거부하십시오. 그리고이 데이터를 서버에 저장하지 않으려면 이전 액세스 데이터를 제거하는 일종의 정리 코드가 필요합니다.

function AccessLogger(n, t, blockTime) { 
    this.qty = n; 
    this.time = t; 
    this.blockTime = blockTime; 
    this.requests = {}; 
    // schedule cleanup on a regular interval (every 30 minutes) 
    this.interval = setInterval(this.age.bind(this), 30 * 60 * 1000); 
} 

AccessLogger.prototype = { 
    check: function(ip) { 
     var info, accessTimes, now, limit, cnt; 

     // add this access 
     this.add(ip); 

     // should always be an info here because we just added it 
     info = this.requests[ip]; 
     accessTimes = info.accessTimes; 

     // calc time limits 
     now = Date.now(); 
     limit = now - this.time; 

     // short circuit if already blocking this ip 
     if (info.blockUntil >= now) { 
      return false; 
     } 

     // short circuit an access that has not even had max qty accesses yet 
     if (accessTimes.length < this.qty) { 
      return true; 
     } 
     cnt = 0; 
     for (var i = accessTimes.length - 1; i >= 0; i--) { 
      if (accessTimes[i] > limit) { 
       ++cnt; 
      } else { 
       // assumes cnts are in time order so no need to look any more 
       break; 
      } 
     } 
     if (cnt > this.qty) { 
      // block from now until now + this.blockTime 
      info.blockUntil = now + this.blockTime; 
      return false; 
     } else { 
      return true; 
     } 

    }, 
    add: function(ip) { 
     var info = this.requests[ip]; 
     if (!info) { 
      info = {accessTimes: [], blockUntil: 0}; 
      this.requests[ip] = info; 
     } 
     // push this access time into the access array for this IP 
     info.accessTimes.push[Date.now()]; 
    }, 
    age: function() { 
     // clean up any accesses that have not been here within this.time and are not currently blocked 
     var ip, info, accessTimes, now = Date.now(), limit = now - this.time, index; 
     for (ip in this.requests) { 
      if (this.requests.hasOwnProperty(ip)) { 
       info = this.requests[ip]; 
       accessTimes = info.accessTimes; 
       // if not currently blocking this one 
       if (info.blockUntil < now) { 
        // if newest access is older than time limit, then nuke the whole item 
        if (!accessTimes.length || accessTimes[accessTimes.length - 1] < limit) { 
         delete this.requests[ip]; 
        } else { 
         // in case an ip is regularly visiting so its recent access is never old 
         // we must age out older access times to keep them from 
         // accumulating forever 
         if (accessTimes.length > (this.qty * 2) && accessTimes[0] < limit) { 
          index = 0; 
          for (var i = 1; i < accessTimes.length; i++) { 
           if (accessTimes[i] < limit) { 
            index = i; 
           } else { 
            break; 
           } 
          } 
          // remove index + 1 old access times from the front of the array 
          accessTimes.splice(0, index + 1); 
         } 
        } 
       } 
      } 
     } 
    } 
}; 

var accesses = new AccessLogger(10, 3000, 15000); 

// put this as one of the first middleware so it acts 
// before other middleware spends time processing the request 
app.use(function(req, res, next) { 
    if (!accesses.check(req.connection.remoteAddress)) { 
     // cancel the request here 
     res.end("No data for you!"); 
    } else { 
     next(); 
    } 
}); 

이 방법은 또한 IP 주소 모니터링 주변의 일반적인 제한이 있습니다

여기 (아이디어를 설명하기 위해 테스트되지 않은 코드)이 할 수있는 방법에 대한 생각입니다. 여러 사용자가 NAT 뒤에서 IP 주소를 공유하는 경우이 사용자를 모두 단일 사용자로 취급하며 단일 사용자의 활동이 아닌 조합 된 활동으로 인해 차단 될 수 있습니다.다른 사람이 말했듯이


는하지만, 시간에 의해 요청은 DOS 손상의 일부는 이미 (이미 서버에서 사이클을 복용) 완료되었습니다, 지금까지 서버에이를 가져옵니다. 데이터베이스 작업과 같이 더 비싼 작업을 수행하기 전에 요청을 차단하는 것이 도움이 될 수 있지만 더 높은 수준 (Nginx 또는 방화벽 또는로드 밸런서)에서이를 탐지하고 차단하는 것이 좋습니다.

2

나는 그렇게 생각하지 않습니다는 HTTP 서버 수준에서 수행해야 무언가이다. 기본적으로 사용자가 15 분 동안 아무 것도 볼 수 없더라도 서버에 도달하는 것을 막을 수는 없습니다.

제 의견으로는 방화벽을 사용하여 시스템 내에서 처리해야합니다. ServerFault 또는 SuperUser에 대한 토론이 더 있지만, 몇 가지 지침을 알려 드리겠습니다. 설정에

  1. 사용 iptables에 당신의 진입 점 (서버 또는 어떤 다른 당신이 라인업에 액세스 할 수 있습니다)에 방화벽. iptables를 사용하면 IP 당 최대 연결 수의 한계를 설정할 수 있습니다. 네트워크에 대한 배경 지식이 없어도 학습 곡선이 꽤 가파르다. 그것이 전통적인 방법입니다. Unix StackExchange

  2. 나는 최근에 그것을 제한 할 수있는 옵션이 일어나는 Uncomplicated Firewall (ufw)라는 정말 좋은 패키지 건너 온 : 당신이 여기에서 필요로하는 무슨에 Iptables for beginners

    과 비슷한 : 여기

    좋은 초보자에 맞도록 자원이다 IP 당 연결 속도이며 분 단위로 설정됩니다. 더 복잡한 것들을 위해 iptables가 여전히 필요합니다. 결론적으로

    , Brad 말했듯이,

    응용 프로그램 서버는 최선을 다해 일을 ... 응용 프로그램을 실행할 수 있습니다.

    그리고 방화벽이 서버에서 원치 않는 IP를 쫓아 내기 위해 최선을 다하도록하십시오.

1

Nodejs를 사용하여 연결을 필터링하거나 연결 정책을 적용하는 것은 좋지 않습니다.

당신이 NodeJS 앞에

클라이언트에서의 Nginx를 사용하는 경우 그것은 더 나은 -> Nginx에 -> Nodejs 또는 응용 프로그램.

Ngnix가 opensource이기 때문에 어렵지 않고 싸지 않습니다.

행운을 비네.

관련 문제