2014-10-10 7 views
7

Ich habe versucht, einen Weg zu finden, um den Schaden auf meiner node.js Anwendung zu minimieren, wenn ich jemals einen DDOS-Angriff bekomme. Ich möchte Anfragen per IP beschränken. Ich möchte jede IP-Adresse auf so viele Anfragen pro Sekunde beschränken. Beispiel: Keine IP-Adresse darf alle 3 Sekunden 10 Anfragen überschreiten.Wie kann die Anzahl der Anfragen pro IP in Node.JS begrenzt werden?

Bisher habe ich mit diesem kommen:

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

Sie können sich gegen ein DOS aber nicht gegen einen DISTRIBUTEDdos Angriff mit dem verteidigen! – loveNoHate

+1

Ich empfehle, Nginx oder etwas vor Ihrem Node.js-Anwendungsserver zu setzen. Sie haben mehr Tools, die effizienter arbeiten und dann können Ihre Anwendungsserver das tun, was sie am besten können ... führen Sie Ihre Anwendung aus. – Brad

Antwort

4

Wenn Sie diese selbst auf dem App-Server-Ebene aufbauen möchten, müssen Sie eine Datenstruktur aufbauen müssen, die jeden letzten Zugriff von einer bestimmten IP-Adresse aufzeichnet, so dass, wenn eine neue Anfrage eintrifft, können Sie zurückblicken durch die Geschichte und sehen, ob es zu viele Anfragen gemacht hat. Wenn ja, leugnen Sie weitere Daten. Und damit sich diese Daten nicht auf Ihrem Server häufen, benötigen Sie auch einen Bereinigungscode, der alte Zugangsdaten löscht.

Hier ist eine Idee für eine Art und Weise, dass (nicht getesteten Code, um die Idee zu illustrieren) zu tun:

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(); 
    } 
}); 

Diese Methode hat auch die üblichen Einschränkungen rund um die IP-Adresse Überwachung. Wenn mehrere Benutzer eine IP-Adresse hinter NAT teilen, werden sie alle als ein einziger Benutzer behandelt, und sie können aufgrund ihrer kombinierten Aktivität blockiert werden, nicht aufgrund der Aktivität eines einzelnen Benutzers.


Aber, wie schon andere gesagt haben, von der Zeit wird die Anfrage so weit in Ihrem Server, hat einige der DOS Schaden bereits geschehen ist (es ist bereits Zyklen von Ihrem Server nehmen). Es kann hilfreich sein, die Anforderung abzubrechen, bevor teurere Operationen wie Datenbankoperationen ausgeführt werden, aber es ist noch besser, diese auf einer höheren Ebene zu erkennen und zu blockieren (wie Nginx oder eine Firewall oder einen Lastenausgleich).

2

Ich glaube nicht, dass ist etwas, das auf dem HTTP-Server-Ebene getan werden sollte. Grundsätzlich verhindert es nicht, dass Benutzer Ihren Server erreichen, auch wenn sie 15 Minuten lang nichts sehen.

Meiner Meinung nach sollten Sie das in Ihrem System behandeln, indem Sie eine Firewall verwenden. Obwohl es eher eine Diskussion für ServerFault oder SuperUser ist, lassen Sie mich Ihnen ein paar Hinweise geben.

  1. Verwenden iptables für das Einrichten eines Firewall auf Ihrem Einstiegspunkt (dem Server oder was auch immer Sie Zugriff haben auf der Linie). Mit iptables können Sie die maximale Anzahl von Verbindungen pro IP festlegen. Die Lernkurve ist ziemlich steil, wenn Sie keinen Hintergrund in Netzwerken haben. Das ist der traditionelle Weg.

    Hier ist eine gute Ressource auf Anfänger ausgerichtet: Iptables for beginners

    Und etwas Ähnliches zu dem, was Sie hier benötigen: Unix StackExchange

  2. ich auf ein wirklich schönes Paket vor kurzem kam Uncomplicated Firewall (ufw) es eine Option haben, zu begrenzen geschieht genannt Verbindungsrate pro IP und ist in Minuten eingerichtet. Für kompliziertere Sachen brauchst du trotzdem iptables.

    Abschließend wie Brad sagte

    lassen Sie Ihre Anwendungsserver tun, was sie am besten können ... Ihre Anwendung ausführen.

    Und lassen Sie Firewalls tun, was sie am besten können, werfen Sie die unerwünschten IPs von Ihren Servern.

1

Es ist nicht gut, wenn Sie mit Nodejs die Verbindung filtern oder die Verbindungsrichtlinie als solche anwenden.

Es ist besser, wenn Sie Nginx vor NodeJS

-Client verwenden -> Nginx -> NodeJS oder Anwendung.

Es ist nicht schwierig und billig, weil Ngnix Opensource Tooo ist.

Viel Glück.

Verwandte Themen