Dreizehn Regeln für die Entwicklung sicherer Java-Anwendungen

Sicherheit ist einer der komplexesten, umfassendsten und wichtigsten Aspekte der Softwareentwicklung. Die Software-Sicherheit wird auch häufig übersehen oder auf wenige geringfügige Anpassungen am Ende des Entwicklungszyklus vereinfacht. Wir können die Ergebnisse in der jährlichen Liste der wichtigsten Verstöße gegen die Datensicherheit sehen, die sich 2019 auf über 3 Milliarden exponierte Datensätze belief. Wenn es Capital One passieren kann, kann es Ihnen passieren.

Die gute Nachricht ist, dass Java eine langjährige Entwicklungsplattform mit vielen integrierten Sicherheitsfunktionen ist. Das Java-Sicherheitspaket wurde intensiven Kampftests unterzogen und wird regelmäßig auf neue Sicherheitslücken aktualisiert. Die neuere Java EE Security API, die im September 2017 veröffentlicht wurde, behebt Schwachstellen in Cloud- und Microservices-Architekturen. Das Java-Ökosystem enthält auch eine breite Palette von Tools zum Profilieren und Melden von Sicherheitsproblemen. 

Aber auch bei einer soliden Entwicklungsplattform ist es wichtig, wachsam zu bleiben. Die Anwendungsentwicklung ist ein komplexes Unterfangen, und Schwachstellen können sich im Hintergrundgeräusch verbergen. Sie sollten in jeder Phase der Anwendungsentwicklung über Sicherheit nachdenken, von Sprachfunktionen auf Klassenebene bis hin zur API-Endpunktautorisierung.

Die folgenden Grundregeln bieten eine gute Grundlage für die Erstellung sicherer Java-Anwendungen.

Java-Sicherheitsregel Nr. 1: Schreiben Sie sauberen, starken Java-Code

Sicherheitslücken verstecken sich gerne in der Komplexität. Halten Sie Ihren Code daher so einfach wie möglich, ohne die Funktionalität zu beeinträchtigen. Wenn Sie bewährte Designprinzipien wie DRY verwenden (wiederholen Sie sich nicht), können Sie Code schreiben, der leichter auf Probleme überprüft werden kann.  

Stellen Sie immer so wenig Informationen wie möglich in Ihrem Code bereit. Durch das Ausblenden von Implementierungsdetails wird Code unterstützt, der sowohl wartbar als auch sicher ist. Diese drei Tipps tragen wesentlich zum Schreiben von sicherem Java-Code bei:

  • Nutzen Sie die Zugriffsmodifikatoren von Java . Wenn Sie wissen, wie Sie verschiedene Zugriffsebenen für Klassen, Methoden und deren Attribute deklarieren, können Sie Ihren Code erheblich schützen. Alles, was privat gemacht werden kann, sollte privat sein. 
  • Vermeiden Sie Reflexion und Selbstbeobachtung . Es gibt einige Fälle, in denen solche fortgeschrittenen Techniken verdient sind, aber zum größten Teil sollten Sie sie vermeiden. Durch die Verwendung von Reflection wird eine starke Eingabe vermieden, die zu Schwachstellen und Instabilität Ihres Codes führen kann. Das Vergleichen von Klassennamen als Zeichenfolgen ist fehleranfällig und kann leicht zu einer Namespace-Kollision führen.
  • Definieren Sie immer die kleinstmöglichen API- und Schnittstellenoberflächen . Entkoppeln Sie Komponenten und lassen Sie sie auf kleinstem Raum interagieren. Selbst wenn ein Bereich Ihrer Anwendung durch einen Verstoß infiziert ist, sind andere sicher. 

Java-Sicherheitsregel Nr. 2: Vermeiden Sie Serialisierung

Dies ist ein weiterer Codierungstipp, der jedoch wichtig genug ist, um eine eigene Regel zu sein. Die Serialisierung nimmt eine Remote-Eingabe und wandelt sie in ein vollständig ausgestattetes Objekt um. Es verzichtet auf Konstruktoren und Zugriffsmodifikatoren und ermöglicht, dass ein Strom unbekannter Daten in der JVM zu Code wird. Infolgedessen ist die Java-Serialisierung zutiefst und von Natur aus unsicher.

Das Ende der Java-Serialisierung

Wenn Sie nicht gehört haben, hat Oracle langfristige Pläne, die Serialisierung von Java zu entfernen. Mark Reinhold, Chefarchitekt der Java-Plattformgruppe bei Oracle, glaubt, dass ein Drittel oder mehr aller Java-Schwachstellen mit Serialisierung verbunden sind.

Vermeiden Sie so weit wie möglich Serialisierung / Deserialisierung in Ihrem Java-Code. Verwenden Sie stattdessen ein Serialisierungsformat wie JSON oder YAML. Stellen Sie niemals einen ungeschützten Netzwerkendpunkt bereit, der einen Serialisierungsstrom empfängt und darauf reagiert. Dies ist nichts anderes als eine willkommene Matte für Chaos.

Java-Sicherheitsregel Nr. 3: Legen Sie niemals unverschlüsselte Anmeldeinformationen oder PII offen

Es ist kaum zu glauben, aber dieser vermeidbare Fehler verursacht Jahr für Jahr Schmerzen.

Wenn ein Benutzer ein Kennwort in den Browser eingibt, wird es als Klartext an Ihren Server gesendet. Das sollte das letzte Mal sein, dass es das Licht der Welt erblickt. Sie müssen das Kennwort über eine Einweg-Verschlüsselung verschlüsseln, bevor Sie es in der Datenbank speichern, und es dann erneut ausführen, wenn Sie es mit diesem Wert vergleichen.

Die Regeln für Passwörter gelten für alle personenbezogenen Daten (PII): Kreditkarten, Sozialversicherungsnummern usw. Alle Ihrer Bewerbung anvertrauten personenbezogenen Daten sollten mit größter Sorgfalt behandelt werden.

Unverschlüsselte Anmeldeinformationen oder PII in einer Datenbank sind eine klaffende Sicherheitslücke, die darauf wartet, dass ein Angreifer sie entdeckt. Schreiben Sie niemals unformatierte Anmeldeinformationen in ein Protokoll oder übertragen Sie sie auf andere Weise in eine Datei oder ein Netzwerk. Erstellen Sie stattdessen einen gesalzenen Hash für Ihre Passwörter. Stellen Sie sicher, dass Sie Ihre Recherchen durchführen und einen empfohlenen Hashing-Algorithmus verwenden.

Springen Sie zu Regel 4: Verwenden Sie immer eine Bibliothek zur Verschlüsselung. Rollen Sie nicht Ihre eigenen.

Java-Sicherheitsregel 4: Verwenden Sie bekannte und getestete Bibliotheken

Bewundern Sie diese Frage und Antwort zum Rollen Ihres eigenen Sicherheitsalgorithmus. Die Lektion lautet: Verwenden Sie nach Möglichkeit bekannte, zuverlässige Bibliotheken und Frameworks. Dies gilt für das gesamte Spektrum, vom Kennwort-Hashing bis zur REST-API-Autorisierung.

Glücklicherweise haben Java und sein Ökosystem hier Ihren Rücken. Für die Anwendungssicherheit ist Spring Security der De-facto-Standard. Es bietet eine breite Palette von Optionen und die Flexibilität, sich an jede App-Architektur anzupassen, und beinhaltet eine Reihe von Sicherheitsansätzen.

Ihr erster Instinkt bei der Bekämpfung der Sicherheit sollte darin bestehen, Ihre Forschung zu betreiben. Erforschen Sie Best Practices und dann, welche Bibliothek diese Praktiken für Sie implementiert. Wenn Sie beispielsweise JSON-Web-Token zum Verwalten der Authentifizierung und Autorisierung verwenden möchten, sehen Sie sich die Java-Bibliothek an, in der JWT enthalten ist, und erfahren Sie, wie Sie diese in Spring Security integrieren.

Selbst mit einem zuverlässigen Tool ist es ziemlich einfach, die Autorisierung und Authentifizierung zu verpfuschen. Bewegen Sie sich langsam und überprüfen Sie alles, was Sie tun.

Java-Sicherheitsregel Nr. 5: Seien Sie paranoid gegenüber externen Eingaben

Ob es sich um einen Benutzer handelt, der in ein Formular, einen Datenspeicher oder eine Remote-API eingibt, vertrauen Sie niemals externen Eingaben.

SQL-Injection und Cross-Site-Scripting (XSS) sind nur die bekanntesten Angriffe, die sich aus der falschen Behandlung externer Eingaben ergeben können. Ein weniger bekanntes Beispiel - eines von vielen - ist der "Milliarden-Lacher-Angriff", bei dem die Erweiterung der XML-Entität einen Denial-of-Service-Angriff verursachen kann.

Jedes Mal, wenn Sie Eingaben erhalten, sollten diese auf ihre Richtigkeit überprüft und bereinigt werden. Dies gilt insbesondere für alles, was einem anderen Tool oder System zur Verarbeitung vorgelegt werden könnte. Zum Beispiel, wenn etwas als Argument für eine OS-Befehlszeile auftauchen könnte: Vorsicht!

Eine spezielle und bekannte Instanz ist die SQL-Injection, die in der nächsten Regel behandelt wird.

Java-Sicherheitsregel Nr. 6: Verwenden Sie immer vorbereitete Anweisungen, um mit SQL-Parametern umzugehen

Jedes Mal, wenn Sie eine SQL-Anweisung erstellen, besteht die Gefahr, dass ein Fragment ausführbaren Codes interpoliert wird.

In diesem Wissen empfiehlt es sich , immer die Klasse java.sql.PreparedStatement zum Erstellen von SQL zu verwenden. Ähnliche Funktionen gibt es für NoSQL-Stores wie MongoDB. Wenn Sie eine ORM-Schicht verwenden, verwendet die Implementierung PreparedStatements für Sie unter der Haube.

Java-Sicherheitsregel Nr. 7: Geben Sie die Implementierung nicht über Fehlermeldungen an

Fehlermeldungen in der Produktion können eine fruchtbare Informationsquelle für Angreifer sein. Insbesondere Stapelspuren können Informationen über die von Ihnen verwendete Technologie und deren Verwendung enthalten. Vermeiden Sie es, Endbenutzern Stapelspuren anzuzeigen.

Benachrichtigungen über fehlgeschlagene Anmeldungen fallen ebenfalls in diese Kategorie. Es ist allgemein anerkannt, dass eine Fehlermeldung als "Anmeldung fehlgeschlagen" oder "Benutzer nicht gefunden" oder "Falsches Kennwort" angezeigt werden sollte. Bieten Sie potenziell schändlichen Benutzern so wenig Hilfe wie möglich an.

Im Idealfall sollten Fehlermeldungen nicht den zugrunde liegenden Technologie-Stack für Ihre Anwendung anzeigen. Halten Sie diese Informationen so undurchsichtig wie möglich.

Java-Sicherheitsregel Nr. 8: Halten Sie Sicherheitsversionen auf dem neuesten Stand

Ab 2019 hat Oracle ein neues Lizenzierungsschema und einen neuen Release-Zeitplan für Java implementiert. Unglücklicherweise für Entwickler macht die neue Release-Trittfrequenz die Dinge nicht einfacher. Sie sind jedoch dafür verantwortlich, regelmäßig nach Sicherheitsupdates zu suchen und diese auf Ihre JRE und Ihr JDK anzuwenden.

Stellen Sie sicher, dass Sie wissen, welche wichtigen Patches verfügbar sind, indem Sie regelmäßig auf der Oracle-Startseite nach Sicherheitswarnungen suchen. Oracle liefert vierteljährlich ein automatisiertes Patch-Update für die aktuelle LTS-Version (Long Term Support) von Java. Das Problem ist, dass dieser Patch nur verfügbar ist, wenn Sie für eine Java-Supportlizenz bezahlen.

Wenn Ihre Organisation für eine solche Lizenz bezahlt, folgen Sie der Route für die automatische Aktualisierung. Wenn nicht, verwenden Sie wahrscheinlich OpenJDK und müssen das Patchen selbst durchführen. In diesem Fall können Sie den Binär-Patch anwenden oder einfach Ihre vorhandene OpenJDK-Installation durch die neueste Version ersetzen. Alternativ können Sie ein kommerziell unterstütztes OpenJDK wie Azul's Zulu Enterprise verwenden.

Benötigen Sie jeden Sicherheitspatch?

Wenn Sie die Sicherheitswarnungen genau beobachten, werden Sie möglicherweise feststellen, dass Sie keine bestimmten Updates benötigen. Beispielsweise scheint die Version vom Januar 2020 ein kritisches Java-Update zu sein. Eine genaue Lektüre zeigt jedoch, dass das Update nur Lücken in der Java-Applet-Sicherheit behebt und keine Auswirkungen auf Java-Server hat.

Java-Sicherheitsregel Nr. 9: Suchen Sie nach Sicherheitslücken in Bezug auf Abhängigkeiten

Es stehen viele Tools zur Verfügung, mit denen Sie Ihre Codebasis und Abhängigkeiten automatisch auf Schwachstellen überprüfen können. Alles was Sie tun müssen, ist sie zu benutzen.

OWASP, das Open Web Application Security Project, ist eine Organisation, die sich der Verbesserung der Codesicherheit widmet. Die Liste der vertrauenswürdigen, hochwertigen automatisierten Code-Scan-Tools von OWASP enthält mehrere Java-orientierte Tools.

Überprüfen Sie Ihre Codebasis regelmäßig, aber behalten Sie auch die Abhängigkeiten von Drittanbietern im Auge. Angreifer zielen sowohl auf Open- als auch auf Closed-Source-Bibliotheken. Achten Sie auf Aktualisierungen Ihrer Abhängigkeiten und aktualisieren Sie Ihr System, sobald neue Sicherheitskorrekturen veröffentlicht werden.

Java-Sicherheitsregel Nr. 10: Überwachen und Protokollieren der Benutzeraktivität

Selbst ein einfacher Brute-Force-Angriff kann erfolgreich sein, wenn Sie Ihre Anwendung nicht aktiv überwachen. Verwenden Sie Überwachungs- und Protokollierungstools, um den Zustand der App im Auge zu behalten.

Wenn Sie davon überzeugt sein möchten, warum Überwachung wichtig ist, schauen Sie sich einfach die TCP-Pakete auf dem Überwachungsport Ihrer Anwendungen an. Sie werden alle Arten von Aktivitäten sehen, weit über einfache Benutzerinteraktionen hinaus. Einige dieser Aktivitäten werden Bots und Übeltäter sein, die nach Schwachstellen suchen.

Sie sollten protokollieren und auf fehlgeschlagene Anmeldeversuche überwachen und Gegenmaßnahmen ergreifen, um zu verhindern, dass Remoteclients ungestraft angreifen.

Durch die Überwachung können Sie auf ungeklärte Spitzen aufmerksam gemacht werden, und durch die Protokollierung können Sie herausfinden, was nach einem Angriff schief gelaufen ist. Das Java-Ökosystem umfasst eine Vielzahl kommerzieller und Open Source-Lösungen für die Protokollierung und Überwachung.

Java-Sicherheitsregel Nr. 11: Achten Sie auf Denial-of-Service-Angriffe (DoS)

Jedes Mal, wenn Sie potenziell teure Ressourcen verarbeiten oder potenziell teure Vorgänge ausführen, sollten Sie sich vor einer außer Kontrolle geratenen Ressourcennutzung schützen.

Oracle führt eine Liste potenzieller Vektoren für diese Art von Problem in seinem Dokument Secure Coding Guidelines for Java SE unter der Überschrift "Denial Of Service".

Grundsätzlich sollten Sie jedes Mal, wenn Sie einen teuren Vorgang ausführen, z. B. das Entpacken einer komprimierten Datei, überwachen, ob die Ressourcennutzung explodiert. Vertraue keinen Dateimanifesten. Vertrauen Sie nur dem tatsächlichen Verbrauch auf der Festplatte oder im Arbeitsspeicher, überwachen Sie ihn und schützen Sie sich vor Überschüssen, die den Server in die Knie zwingen.

In ähnlicher Weise ist es bei einigen Verarbeitungen wichtig, auf unerwartete Forever-Schleifen zu achten. Wenn eine Schleife verdächtig ist, fügen Sie einen Schutz hinzu, der sicherstellt, dass die Schleife Fortschritte macht, und schließen Sie sie kurz, wenn sie als Zombie eingestuft wurde.

Java-Sicherheitsregel Nr. 12: Verwenden Sie möglicherweise den Java-Sicherheitsmanager

Java verfügt über einen Sicherheitsmanager, mit dem die Ressourcen eingeschränkt werden können, auf die ein laufender Prozess Zugriff hat. Es kann das Programm in Bezug auf Festplatten-, Speicher-, Netzwerk- und JVM-Zugriff isolieren. Durch Eingrenzen dieser Anforderungen für Ihre App wird der Fußabdruck möglicher Schäden durch einen Angriff verringert. Eine solche Isolierung kann auch unpraktisch sein, weshalb sie SecurityManagerstandardmäßig nicht aktiviert ist.

Sie müssen selbst entscheiden, ob SecurityManagerdas Umgehen der starken Meinungen den zusätzlichen Schutz für Ihre Anwendungen wert ist. Weitere Informationen zur Syntax und zu den Funktionen des Java-Sicherheitsmanagers finden Sie in den Oracle-Dokumenten.

Java-Sicherheitsregel Nr. 13: Erwägen Sie die Verwendung eines externen Cloud-Authentifizierungsdienstes

Einige Anwendungen müssen lediglich ihre Benutzerdaten besitzen. Im Übrigen könnte ein Cloud-Dienstanbieter sinnvoll sein.

Durchsuchen Sie die Umgebung und finden Sie eine Reihe von Cloud-Authentifizierungsanbietern. Der Vorteil eines solchen Dienstes besteht darin, dass der Anbieter für die Sicherung sensibler Benutzerdaten verantwortlich ist, nicht Sie. Andererseits erhöht das Hinzufügen eines Authentifizierungsdienstes die Komplexität Ihrer Unternehmensarchitektur. Einige Lösungen, wie die FireBase-Authentifizierung, enthalten SDKs für die Integration über den Stapel.

Fazit

Ich habe 13 Regeln für die Entwicklung sicherer Java-Anwendungen vorgestellt. Diese Regeln haben sich bewährt, aber die größte Regel von allen lautet: Seien Sie misstrauisch. Gehen Sie bei der Softwareentwicklung immer vorsichtig und sicherheitsbewusst vor. Suchen Sie nach Schwachstellen in Ihrem Code, nutzen Sie die Java-Sicherheits-APIs und -Pakete und verwenden Sie Tools von Drittanbietern, um Ihren Code auf Sicherheitsprobleme zu überwachen und zu protokollieren.

Hier sind drei gute Ressourcen auf hoher Ebene, um mit der sich ständig ändernden Java-Sicherheitslandschaft Schritt zu halten:

  • OWASP Top 10
  • CWE Top 25
  • Richtlinien für sicheren Code von Oracle

Diese Geschichte "Dreizehn Regeln für die Entwicklung sicherer Java-Anwendungen" wurde ursprünglich von JavaWorld veröffentlicht.