Sicherheitsartikel für Entwickler haben ein Grundproblem: Sie beginnen bei den spektakulären Angriffen und enden bei einer Checkliste, die für ein Projekt mit zweihundert Nutzern maßlos wirkt. In echten kleinen Anwendungen sieht die Realität anders aus — es sind fast immer dieselben vier, fünf Fehler, und keiner davon ist besonders raffiniert.
Das hier ist die Liste, die ich abarbeite, bevor ein Projekt live geht. Nicht vollständig, aber nach Wirkung sortiert.
Der Fehler Nummer eins: fehlende Zugriffsprüfung
Der häufigste ernsthafte Fehler in kleinen Anwendungen ist nicht Einschleusung von Code, sondern eine Zugriffsprüfung, die es nicht gibt. Konkret: Ein Endpunkt prüft, ob jemand eingeloggt ist, aber nicht, ob dieser jemand auf genau dieses Objekt zugreifen darf.
Das Muster ist immer gleich. Die Adresse enthält eine Kennung — eine Rechnungsnummer, eine Projekt-Kennung, eine Nutzer-Kennung — und der Code lädt das Objekt anhand dieser Kennung, ohne zu prüfen, wem es gehört. Zähl die Nummer hoch, und du siehst fremde Daten. Das ist trivial auszunutzen und wird bei kleinen Anwendungen praktisch nie durch Zufall entdeckt, sondern erst dann, wenn jemand gezielt sucht.
Die Gegenmaßnahme ist nicht Sorgfalt, sondern Struktur: Lade Objekte grundsätzlich mit dem Besitzverhältnis als Teil der Abfrage, nicht als nachgelagerte Prüfung. Wer die Zugehörigkeit in die Datenzugriffs-Schicht zieht, kann sie nicht mehr an einer einzelnen Stelle vergessen. Und beim Testen: Leg zwei Testkonten an und versuche systematisch, mit Konto A auf die Objekte von Konto B zuzugreifen. Das ist der wirkungsvollste Sicherheitstest, den du in einer halben Stunde machen kannst.
Verwandt dazu: Prüfungen, die nur im Frontend stattfinden. Ein ausgeblendeter Button ist keine Berechtigung. Alles, was die Oberfläche versteckt, muss der Server nochmal ablehnen.
Eingaben: Was moderne Werkzeuge dir abnehmen — und was nicht
Wer heute ein ordentliches Datenbank-Werkzeug mit parametrisierten Abfragen nutzt und ein Frontend-Framework, das Ausgaben standardmäßig maskiert, hat einen großen Teil der klassischen Einschleusungs-Lücken bereits nicht. Das ist echter Fortschritt — er macht aber blind für die Stellen, an denen man den Schutz selbst aushebelt.
Die typischen Ausnahmen: selbst zusammengebaute Abfragen für den einen dynamischen Sortier- oder Suchfall; das Einsetzen von unmaskiertem HTML, weil ein Kunde formatierte Texte pflegen können soll; Vorlagen, in denen Werte per Zeichenkettenverkettung landen. Genau an diesen Stellen sitzen die Lücken, und es sind immer die Stellen, an denen jemand eine Abkürzung genommen hat.
Wenn Nutzer HTML liefern dürfen, führt kein Weg an einer etablierten Bereinigungs-Bibliothek vorbei — mit einer Positivliste erlaubter Elemente und Attribute, nicht mit einer Sperrliste. Sperrlisten für gefährliche Muster wurden noch nie vollständig.
Abhängigkeiten sind dein größtes Einfallstor
Der Code, den du selbst schreibst, ist ein Bruchteil dessen, was in deiner Anwendung läuft. Der Rest sind Pakete, deren Pakete und deren Pakete.
Das Minimum: eine automatisierte Prüfung der Abhängigkeiten in der Pipeline und ein Bot, der Aktualisierungen als Änderungsvorschlag einstellt. Wichtiger als das Werkzeug ist die Gewohnheit, diese Vorschläge tatsächlich regelmäßig einzuspielen. Ein Projekt, das zwei Jahre nicht aktualisiert wurde, lässt sich nicht mehr in einem Rutsch nachziehen — dann steht plötzlich ein Wochenende Migrationsarbeit an, und deshalb bleibt es wieder liegen.
Zwei Ergänzungen: Achte beim Hinzufügen neuer Pakete darauf, wie viel sie mitbringen. Ein Paket mit vierzig Unterabhängigkeiten für eine Funktion, die zwanzig Zeilen wären, ist ein schlechter Handel. Und pinne deine Versionen über eine Sperrdatei, damit ein Build heute dasselbe installiert wie letzte Woche.
Secrets, Konfiguration und die Standardeinstellungen
Zugangsdaten im Repository sind der Klassiker, der immer noch passiert — besonders in .env-Dateien, die versehentlich eingecheckt werden, und in Konfigurationsbeispielen, in denen “nur zum Testen” echte Schlüssel stehen. Wichtig zu wissen: Ein Schlüssel, der einmal im Git-Verlauf war, ist kompromittiert. Ihn im nächsten Commit zu entfernen reicht nicht, er muss beim Anbieter zurückgezogen werden.
Dazu die Einstellungen, die in Produktion anders sein müssen als lokal: Fehlerseiten dürfen keine Stacktraces und keine Konfiguration ausgeben; Debug-Modi gehören aus; Datenbank- und Administrationsoberflächen dürfen nicht öffentlich erreichbar sein. Ein erstaunlich großer Teil dessen, was Angreifer über automatisierte Scans finden, sind schlicht offene Verwaltungsoberflächen und Statusseiten, die niemand absichtlich veröffentlicht hat.
Ratenbegrenzung gehört ebenfalls hierher, mindestens auf Login, Passwort-Zurücksetzen, Registrierung und alle Endpunkte, die Mails verschicken. Ohne sie ist dein Kontaktformular ein Werkzeug zum Versenden fremder Nachrichten und dein Login eine Einladung, Passwortlisten durchzuprobieren.
Datei-Uploads: klein, aber gefährlich
Wenn deine Anwendung Uploads erlaubt, brauchst du drei Regeln. Erstens: Vertraue niemals dem Dateinamen und niemals dem vom Browser gemeldeten Dateityp. Generiere eigene Namen und prüfe den tatsächlichen Inhalt. Zweitens: Lege Uploads nicht in ein Verzeichnis, aus dem der Webserver Dateien ausführen kann. Drittens: Setz Größenbegrenzungen, sonst ist der Upload ein Weg, deine Festplatte zu füllen.
Und wenn Uploads privat sein sollen, dann müssen sie es auch sein: eine zufällige, schwer zu erratende Adresse ist keine Zugriffskontrolle, wenn die Datei ohne Prüfung ausgeliefert wird. Solche Adressen landen in Verläufen, Weiterleitungen und Suchmaschinen.
Der realistische Maßstab
Du wirst kein Projekt bauen, das gegen einen gezielten, gut ausgestatteten Angriff standhält — und für die meisten kleinen Anwendungen ist das auch nicht das Bedrohungsmodell. Was dich tatsächlich trifft, sind automatisierte Scans, die bekannte Lücken und offene Türen suchen, und Neugierige, die an Kennungen in Adressen drehen.
Gegen genau diese beiden Gruppen wirken die Punkte oben fast vollständig. Sie kosten dich zusammen vielleicht einen Tag, verteilt über ein Projekt. Und wenn du danach noch Kapazität hast, ist die beste nächste Investition nicht ein weiteres Werkzeug, sondern jemand anderes, der einmal drüberschaut: Fremde Augen finden in einer Stunde Dinge, an denen du seit Monaten vorbeiliest.
Wenn du dafür jemanden suchst — im Discord der Community schauen sich Leute gegenseitig regelmäßig Projekte an, bevor sie live gehen.