Hallo,
ich erstelle gerade ein Webprojekt mit Datenbank und da kam die Frage
auf, wie man üblicherweise verhindert, dass ein User die Datenbank nicht
flutet.
Beispielweise könnte jemand ja einfach ein Skript schreiben, dass alle
100ms einen Datensatz von 100kb einträgt und damit die Datenbank sinnlos
füllt. Merkt der Admin das 1 Tag nicht, wäre die Datenbank in 24h dann
86GB größer und man hat die Arbeit das wieder aufzuräumen.
Das Problem müssten doch viele habe und deshalb muss es da doch einen
Standard-Weg geben, um sowas zu verhindern. Bieten Frameworks wie zum
Beispiel Laravel bei PHP so etwas schon im Kern?
Pepe
Interessante Frage. Das ist eine der Fragen, die sich "normale"
Softwareentwickler nicht stellen. Klar ist auch, dass das ein echtes
Problem ist, denn eine derart aufgeblähte Datenbank wird langsam. Ich
sehe aber rein technisch schon keinen einfachen Weg das zu verhindern.
Angenommen, eine Applikation lässt Benutzerregistrierungen oder
unregistrierte Postings zu, dann könnte man maximal etwas auf Basis der
IP Adresse realisieren. Die ist aber in Zeiten von IPv4 Knappheit alles
andere als verlässlich. Wer dagegen seine Benutzer kennt, hat das
Problem wahrscheinlich eher nicht.
Insgesamt scheint das in der Praxis derzeit kein relevantes Problem zu
sein. Möglicherweise auch deshalb, weil DDoS Angriffe viel einfacher und
billig zu haben ist.
Es gibt Möglichkeiten Rate Limits für Datenbankverbindungen zu
implementieren. Da leiden dann aber sofort alle Nutzer drunter. Ist also
auch keine echte Lösung.
Wenn ich eine solche Überschrift lese... jemand such eine
"Web-Technologie".... von welchem Ministerium bist du? Bestimmt vom
Zukunfts-Innovations-Ministerium für Ferndatendirektverarbeitung
Deutschlands.
Einfach mal Hirn einschalten, dann kommt der Rest von selbst.
Sowas banales....
Pepe_Ku schrieb:> Beispielweise könnte jemand ja einfach ein Skript schreiben, dass alle> 100ms einen Datensatz von 100kb einträgt und damit die Datenbank sinnlos> füllt. Merkt der Admin das 1 Tag nicht, wäre die Datenbank in 24h dann> 86GB größer und man hat die Arbeit das wieder aufzuräumen.
Warum kann denn da jeder einfach so über das Web in dieser Rate solche
Datensätze anlegen?
Pepe_Ku schrieb:> Das Problem müssten doch viele habe und deshalb muss es da doch einen> Standard-Weg geben, um sowas zu verhindern.
Der erste Weg liegt in der Überwachung der Systeme und entsprechender
Benachrichtigung. Hier also mindestens vom Plattenplatz des Servers, um
möglichst rechtzeitig reagieren zu können.
Standard ist Festplatte Kontingentierung (quota} und Überwachung des
Dienstes sowie der Limits, auch vor dem Erreichen der Limits. Framework
war früher in perl geschrieben, CGI+Cron+smtp. Für Win gibt es einen
entsprechenden Service und SMTP exe. Welcher professionelle Hoster
betreibt denn eine DB bzw Nas ohne Quotas und ohne Netzwerkdrosselung?
Pepe_Ku schrieb:> Das Problem müssten doch viele habe und deshalb muss es da doch einen> Standard-Weg geben, um sowas zu verhindern. Bieten Frameworks wie zum> Beispiel Laravel bei PHP so etwas schon im Kern?
Nein, aber Hirn 1.0 bietet das.
Was ist an maximal n Einträge je Benutzer pro /Tag/Stunde/whatever so
schwer umzusetzen?
Ideal ist in solchen Fällen ein "Leaky Bucket Filter".
Gedankenmodell ist hier ein Eimer (mit einer bestimmten Größe), der mit
einer bestimmten festen Rate nachgefüllt wird. Wenn dann ein Datensatz
angelegt werden soll entnimmt man ein Token aus dem Eimer bis der leer
ist.
Man kann sich aussuchen, was der Eimerinhalt repräsentiert. Ein Token im
Eimer kann z.B. für einen ganzen Datensatz stehen oder für einzelne
Bytes.
Leere Eimer sollten ins Log, und darauf basierend kann man dann ggf.
Alerting machen.
Dann macht man mehrere dieser Limits: z.B. ein Limit pro User, pro IP
und allgemein oder pro Anwendungsbereich.
In der Implementierung persistiert man natürlich nur nicht-leere Eimer.
Wenn Leaky-Bucket zu kompliziert ist kann man auch einfach stumpf zählen
und harte Limits vorgeben, und die Zähler zyklisch resetten.
Pepe_Ku schrieb:> Beispielweise könnte jemand ja einfach ein Skript schreiben, dass alle> 100ms einen Datensatz von 100kb einträgt und damit die Datenbank sinnlos> füllt.
Das klingt nach dem ersten Problem bei deinem Design, nicht jeder sollte
alles in deine Datenbank eintragen dürfen. Wenn ich deine Datenbank mit
ein Script massieren darf, wäre meine Intention aber auch nicht der
flood, sondern die SQL Injektion. Die meisten Benutzer verwenden den
gleichen Datensatz immer wieder, das ist doch viel wertvoller als den
Admin zu ärgern und vielleicht, kann man den Server ja auch übernehmen.
Außerdem gibt es sowas wie thresholds und ratelimit, das ein Flood
verhindern sollte.
Pepe_Ku schrieb:> Merkt der Admin das 1 Tag nicht, wäre die Datenbank in 24h dann> 86GB größer und man hat die Arbeit das wieder aufzuräumen.
Der Admin sollte seine Systeme Monitoren, es gibt keine Entschuldigung
das nicht zu tun! Wenn also die Datenbank so schnell anwächst (und der
Traffic, und die Systemload) sollte der Admin eine Benachrichtigung,
bekommen und geeignete Gegenmaßnahmen ergreifen. Nagios, Icinga und wie
sie alle heißen, können auch SMS verschicken, um angemessen zu reagieren
und spätesten, wenn das noch mit einem ELK Stack ergänzt wird oder mit
influxdb und Grafana, sollte bei entsprechend gepflegten Monitoring, der
Admin in nahezu Echtzeit über den Zustand seines Systems Bescheid wissen
und nach ein paar Minuten denn Flood automatisch erkennen.
Pepe_Ku schrieb:> ich erstelle gerade ein Webprojekt mit Datenbank und da kam die Frage> auf, wie man üblicherweise verhindert, dass ein User die Datenbank nicht> flutet.
Indem man die DB nicht direkt öffentlich macht.
Tilos Ansatz gefällt mir auch gut. Zu den restlichen Schwachmaten hier
sage ich jetzt mal lieber nichts. Ich sehe aber, dass dieser Ansatz neue
DoS Möglichkeiten einbaut. Ich kann mir trivial für wenige Cent
unterschiedlichste IP Adressen zulegen und damit z.B. absurd viele
unterschiedliche Benutzer registrieren.
Dann ist zwar irgendwann der Eimer für Registrierungen leer, aber dann
kann sich eben auch kein anderer mehr Registrieren. Das ist sicher das
geringere Übel, aber keine echte Lösung.
Ich würde daher eine zusätzliche Stufe in diesem Modell hinzufügen.
Sobald der Eimer für unautentifzierte Anfragen aufgebraucht ist,
verlangt die Applikation die Eingabe eines Captchas. So sollte sich eine
sinnvolle Balance erreichen lassen.
Ich muss aber auch sagen, dass es nicht viele Applikationen zu geben
scheint, die so etwas implementieren. Ich erinnere mich an einige Fälle
wo genau dieses Fluten der Datenbank über eine aktivierte WordPress
Registrierungsfunktion passiert ist. Mit allen Seiteneffekten wie
unzähligen bouncenden Emails und Abuse Reports.
Nachtrag zur Leaky-Bucket-Implementierung.
Tilo R. schrieb:> In der Implementierung persistiert man natürlich nur nicht-leere Eimer.
Obige Aussage ist falsch formuliert, ich meinte: man persistiert nur
nicht-ganz-volle Eimer. Sonst müsste man alles mögliche initialisieren,
das wäre wenig robust.
Meist hat man eher das Problem dass nicht eingeloggte Robots ev. heftig
lesend auf die DB hämmern, als dass eingeloggte User Unmengen an Daten
in einer DB generieren.
Beim eingeloggten User kann man ja easy nur eine maximale Anzahl an
Einträgen pro Zeiteinheit erlauben.
Im ersten Fall nutzt Caching und Rate Limiting, ggf. Captcha usw.
Für eingeloggte User kann man ebenso Captcha und Rate Limiting
verwenden.
Das kann man dann, wie von Tilo vorgeschlagen, selbst implementieren
oder man nutzt bestehende Framework-Funktionen.
z.B. gibt es in Laravel diverse Rate-Limiting-Funktionalität auf
verschiedenen Ebenen (HTTP/User/Session usw.).