Skip to main content

10 Best Practices für die Java-Sicherheit

Cheat sheet header java

17. September 2019

0 Min. Lesezeit

In dieser Ausgabe unseres Spickzettels geht es um zehn Best Practices für die Java-Sicherheit – sowohl für Open-Source-Maintainer als auch für Entwickler. Dieser Spickzettel ist eine Zusammenarbeit von Brian Vermeer, Developer Advocate bei Snyk, und Jim Manico, Java Champion und Gründer von Manicode Security.

Wir empfehlen Ihnen, den Spickzettel auszudrucken und außerdem mehr über die zehn Java-Sicherheitstipps zu lesen, die wir weiter unten ausführlicher erläutern.

Also, legen wir los!

Sicherheitsprobleme in Java

Auch wenn wir alle darauf abzielen, guten Code zu schreiben, gehört die Java-Sicherheitnicht immer zum Mindset von Entwicklern. Sicherheitsprobleme in Java zu verhindern, sollte jedoch genauso wichtig sein wie die Performance, Skalierbarkeit und Wartbarkeit Ihrer Java-Anwendung.

Achten Sie außerdem auf neuere Sicherheitslücken in Java, etwa Log4Shell (CVE-2021-44228). Diese Sicherheitslücke wurde im Dezember 2021 bekannt und betraf Anwendungen, die anfällige Versionen von Apache Log4j ausführten.

In diesem Spickzettel besprechen wir zehn häufige Sicherheitsprobleme in Java. Wir geben Ihnen praxisnahe Hinweise und Beispiele dazu, wie Sie diese häufigen Java-Sicherheitslücken in Ihren Anwendungen verhindern können.

1. Verwenden Sie Abfrageparameter, um Injection-Angriffe zu verhindern

In der Version der OWASP Top 10-Sicherheitslücken von 2017 stand Injection an der Spitze der Liste und war in diesem Jahr die häufigste Sicherheitslücke. Bei einer typischen SQL-Injection in Java werden die Parameter einer SQL-Abfrage naiv an den statischen Teil der Abfrage angehängt. Das folgende Beispiel zeigt eine unsichere Ausführung von SQL in Java, mit der ein Angreifer mehr Informationen erhalten kann als beabsichtigt.

public void selectExample(String parameter) throws SQLException {
   Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);
   String query = "SELECT * FROM USERS WHERE lastname = " + parameter;
   Statement statement = connection.createStatement();
   ResultSet result = statement.executeQuery(query);

   printResult(result);
}

Wenn der Parameter in diesem Beispiel etwa '' OR 1=1 lautet, enthält das Ergebnis jedes einzelne Element in der Tabelle. Noch problematischer kann es werden, wenn die Datenbank mehrere Abfragen unterstützt und der Parameter ''; UPDATE USERS SET lastname='' lautet.

Um dieses Java-Sicherheitsrisiko zu verhindern, sollten wir die Abfragen mit einer Prepared-Statement-Anweisung parametrisieren. Datenbankabfragen sollten ausschließlich auf diese Weise erstellt werden. Wenn Sie den vollständigen SQL-Code definieren und die Parameter erst später an die Abfrage übergeben, ist der Code leichter verständlich. Vor allem aber lässt sich die Abfrage durch die Trennung von SQL-Code und Parameterdaten nicht durch bösartige Eingaben manipulieren.

public void prepStatmentExample(String parameter) throws SQLException {
   Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);
   String query = "SELECT * FROM USERS WHERE lastname = ?";
   PreparedStatement statement = connection.prepareStatement(query);
   statement.setString(1, parameter);
   System.out.println(statement);
   ResultSet result = statement.executeQuery();

   printResult(result);
}

Im obigen Beispiel wird die Eingabe an den Typ String gebunden und ist daher Teil des Abfragecodes. Mit dieser Technik wird verhindert, dass die Parametereingabe den SQL-Code beeinflusst.

Weitere Informationen zur Verhinderung von SQL-Injections finden Sie in diesem praktischen Leitfaden: Spickzettel zu SQL-Injections: 8 Best Practices, um SQL-Injection-Angriffe zu verhindern

2. Verwenden Sie OpenID Connect mit 2FA

Identitätsmanagement und Zugriffskontrolle sind schwierig, und eine fehlerhafte Authentifizierung ist oft die Ursache für Datenpannen. Tatsächlich steht dieses Thema auf Platz 2 der OWASP-Liste der zehn wichtigsten Sicherheitslücken und ist daher ein erhebliches Java-Sicherheitsrisiko. Wenn Sie die Authentifizierung selbst implementieren, müssen Sie vieles berücksichtigen: sichere Speicherung von Passwörtern, starke Verschlüsselung, Abruf von Anmeldedaten usw. In vielen Fällen ist es einfacher und sicherer, bewährte Lösungen wieOpenID Connect zu verwenden. OpenID Connect (OIDC) ermöglicht Ihnen die Authentifizierung von Nutzern über Websites und Apps hinweg. So müssen Sie keine Passwortdateien besitzen und verwalten. OpenID Connect ist eineOAuth 2.0-Erweiterung, die Nutzerinformationen bereitstellt. Zusätzlich zu einem Zugriffstoken wird ein ID-Token hinzugefügt, ebenso wie ein /userinfo-Endpunkt, über den Sie weitere Informationen abrufen können. Außerdem gibt es eine Endpunkterkennung und die dynamische Clientregistrierung.

OpenID Connect mit Bibliotheken wieSpring Security einzurichten, ist unkompliziert und gängige Praxis. Stellen Sie sicher, dass Ihre Anwendung 2FA (Zwei-Faktor-Authentifizierung) oder MFA (Multi-Faktor-Authentifizierung) erzwingt, um Ihrem System eine zusätzliche Sicherheitsebene hinzuzufügen.

Wenn Sie IhrerSpring Boot-Anwendung die Abhängigkeiten oauth2-client und Spring Security hinzufügen, können Sie Drittanbieter wie Google, GitHub undOkta für die OIDC-Verarbeitung nutzen. Nachdem Sie Ihre Anwendung erstellt haben, müssen Sie sie nur noch mit dem gewünschten Client verbinden. Geben Sie diesen dazu in der Anwendungskonfiguration an. Das kann Ihre GitHub- oder Okta-Client-ID und Ihr Client-Secret sein, wie unten gezeigt.

pom.xml

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

application.yaml

spring:
 security:
   oauth2:
     client:
         registration:
           github:
             client-id: 796b0e5403be4729ca01
             client-secret: f379318daa27502254a05e054361074180b840a9
           okta:
             client-id: 0oa1a4wascEpYu6yk358
             client-secret: hqxj7a9lVe_TudbS2boBW7AWwxTlZiHNrJxdc_Sk
             client-name: Okta
         provider:
           okta:
             issuer-uri: https://dev-844689.okta.com/oauth2/default

3. Prüfen Sie Ihre Abhängigkeiten auf bekannte Sicherheitslücken

Wahrscheinlich wissen Sie nicht, wie viele direkte Abhängigkeiten Ihre Anwendung verwendet. Und noch wahrscheinlicher ist, dass Sie auch die Anzahl der transitiven Abhängigkeiten nicht kennen. Das ist oft der Fall, obwohl Abhängigkeiten den größten Teil Ihrer Anwendung ausmachen. Angreifer nehmen immer häufiger Open-Source-Abhängigkeiten ins Visier, denn durch ihre Wiederverwendung kann ein Angreifer viele Opfer erreichen. Daher ist es wichtig sicherzustellen, dass es im gesamten Abhängigkeitsbaum Ihrer Anwendung keine bekannten Java-Sicherheitslücken gibt.

Snyk prüft die Build-Artefakte Ihrer Anwendung und markiert Abhängigkeiten mit bekannten Sicherheitslücken. In einem Dashboard erhalten Sie eine Liste der Java-Sicherheitslücken in den Paketen, die Ihre Anwendung verwendet.

Snyk-Projektliste mit drei Repositories und einer hohen, mittleren und niedrigen Anzahl an Problemen, Abhängigkeiten, Aktualisierungszeiten und Quellplattformen

Darüber hinaus schlägt Snyk aktualisierte Versionen vor oder stellt Patches bereit, um Ihre Sicherheitsprobleme zu beheben – per Pull Request an Ihr Quellcode-Repository. Snyk schützt Ihre Umgebung außerdem, indem alle zukünftigen Pull Requests in Ihrem Repository automatisch getestet werden (über Webhooks). So wird sichergestellt, dass keine neuen bekannten Sicherheitslücken eingeführt werden.

Snyk ist sowohl über eine Weboberfläche als auch über eine CLI verfügbar. So können Sie Snyk in Ihre CI-Umgebung integrieren und den Build abbrechen lassen, wenn Sicherheitslücken mit einem Schweregrad oberhalb des von Ihnen festgelegten Schwellenwerts gefunden werden.

Nutzen Sie Snyk kostenlos für Open-Source-Projekte oder private Projekte mit einer begrenzten Anzahl monatlicher Tests.

4. Gehen Sie sorgfältig mit sensiblen Daten um

Die Offenlegung sensibler Daten wie personenbezogener Daten oder Kreditkartennummern Ihrer Kunden kann schädlich sein. Aber auch ein weniger offensichtlicher Fall kann ebenso gravierende Folgen haben. Wenn beispielsweise eindeutige Kennungen in Ihrem System offengelegt werden und sich damit über einen anderen Aufruf weitere Daten abrufen lassen, liegt eine Java-Sicherheitslücke vor.

Prüfen Sie zunächst das Design Ihrer Anwendung genau und stellen Sie fest, ob Sie die Daten wirklich benötigen. Achten Sie außerdem darauf, keine sensiblen Daten offenzulegen, etwa durch Protokollierung, Autovervollständigung oder Datenübertragung.

Eine einfache Möglichkeit, zu verhindern, dass sensible Daten in Ihren Protokollen landen, ist die Bereinigung der toString()-Methoden Ihrer Domänenentitäten. So können sensible Felder nicht versehentlich ausgegeben werden. Wenn Sie mit Project Lombok Ihre toString()-Methode generieren, können Sie mit @ToString.Exclude verhindern, dass ein Feld in der toString()-Ausgabe erscheint.

Seien Sie außerdem sehr vorsichtig, wenn Sie Daten nach außen weitergeben. Beispiel: Wenn ein Endpunkt in einem System alle Nutzernamen anzeigt, muss die interne eindeutige Kennung nicht angezeigt werden. Über andere Endpunkte könnte diese Kennung dazu verwendet werden, dem Nutzer weitere, sensiblere Informationen zuzuordnen. Wenn Sie Jackson verwenden, um POJOs in JSON zu serialisieren und zu deserialisieren, können Sie mit @JsonIgnore und @JsonIgnoreProperties verhindern, dass diese Eigenschaften serialisiert oder deserialisiert werden.

Wenn Sie sensible Daten an andere Services senden müssen, verschlüsseln Sie diese ordnungsgemäß und stellen Sie sicher, dass Ihre Verbindung beispielsweise mit HTTPS gesichert ist.

5. Bereinigen Sie sämtliche Eingaben

Cross-Site-Scripting (XSS) ist ein bekanntes Problem, das vor allem bei JavaScript-Anwendungen ausgenutzt wird. Java ist jedoch nicht immun dagegen. Bei XSS wird JavaScript-Code eingeschleust, der aus der Ferne ausgeführt wird. Regel Nr. 0 zur Verhinderung von XSS lautet laut OWASP: „Fügen Sie nicht vertrauenswürdige Daten niemals außerhalb der zulässigen Stellen ein.“ Die grundlegende Lösung für dieses Java-Sicherheitsrisiko besteht darin, nicht vertrauenswürdige Daten so weit wie möglich zu vermeiden und alle übrigen Daten vor der Verwendung zu bereinigen. Ein guter Ausgangspunkt ist die OWASP Java Encoding Library, die zahlreiche Encoder bereitstellt.

<dependency>
   <groupId>org.owasp.encoder</groupId>
   <artifactId>encoder</artifactId>
   <version>1.2.2</version>
</dependency>
String untrusted = "<script> alert(1); </script>";
System.out.println(Encode.forHtml(untrusted));

// output: <script> alert(1); </script>

Nutzereingaben in Textform zu bereinigen, liegt auf der Hand. Aber was ist mit Daten, die Sie aus einer Datenbank abrufen – selbst wenn es Ihre eigene Datenbank ist? Was, wenn Ihre Datenbank kompromittiert wurde und jemand bösartigen Text in einem Datenbankfeld oder Dokument hinterlassen hat?

Behalten Sie auch eingehende Dateien im Blick. DieZip-Slip-Sicherheitslücke in vielen Bibliotheken entsteht, weil der Pfad der komprimierten Dateien nicht bereinigt wurde. ZIP-Dateien mit Dateien unter Pfaden wie ../../../../foo.xy könnten entpackt werden und möglicherweise beliebige Dateien überschreiben. Auch wenn dies kein XSS-Angriff ist, zeigt es doch, warum Sie sämtliche Eingaben bereinigen müssen. Jede Eingabe kann potenziell bösartig sein und sollte entsprechend bereinigt werden.

6. Konfigurieren Sie Ihre XML-Parser so, dass XXE verhindert wird

Wenn XML External Entities (XXE) aktiviert sind, lässt sich eine bösartige XML-Datei wie die folgende erstellen, um den Inhalt beliebiger Dateien auf dem Rechner auszulesen. Es überrascht nicht, dass XXE-Angriffe zu den OWASP Top 10 gehören und eine Java-Sicherheitslücke darstellen, die verhindert werden muss. Java-XML-Bibliotheken sind besonders anfällig für XXE-Injections, da bei den meisten XML-Parsern externe Entitäten standardmäßig aktiviert sind.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE bar [
       <!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<song>
   <artist>&xxe;</artist>
   <title>Bohemian Rhapsody</title>
   <album>A Night at the Opera</album>
</song>

Eine naive Implementierung des DefaultHandler und des Java-SAX-Parsers wie die unten gezeigte analysiert diese XML-Datei und gibt den Inhalt der passwd-Datei preis. Hier dient der Java-SAX-Parser als Hauptbeispiel, doch andere Parser wie DocumentBuilder und DOM4J weisen ein ähnliches Standardverhalten auf.

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();

DefaultHandler handler = new DefaultHandler() {

    public void startElement(String uri, String localName,String qName,Attributes attributes) throws SAXException {
        System.out.println(qName);
    }

    public void characters(char ch[], int start, int length) throws SAXException {
        System.out.println(new String(ch, start, length));
    }
};

Wenn Sie die Standardeinstellungen so ändern, dass externe Entitäten und Doctypes fürxerces1 beziehungsweisexerces2 nicht zugelassen werden, lassen sich solche Angriffe verhindern.

...
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();

factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
saxParser.getXMLReader().setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); 
... 

Praktische Informationen dazu, wie Sie bösartige XXE-Injections verhindern, finden Sie im OWASP-XXE-Spickzettel. Oder sehen Sie sich mein Video zum Thema So verhindern Sie External-Entity-Injection-Angriffe (XXE) an.

Java XML Security: How to prevent External Entity (XXE) Injection attacks

7. Vermeiden Sie die Java-Serialisierung

Mit der Serialisierung in Java können wir ein Objekt in einen Bytestrom umwandeln. Dieser Bytestrom wird entweder auf der Festplatte gespeichert oder an ein anderes System übertragen. Umgekehrt lässt sich ein Bytestrom deserialisieren, sodass das ursprüngliche Objekt wiederhergestellt wird.

Das größte Problem besteht bei der Deserialisierung. Typischerweise sieht das etwa so aus:

ObjectInputStream in = new ObjectInputStream( inputStream );
return (Data)in.readObject();

Vor der Dekodierung können Sie nicht wissen, was Sie deserialisieren. Ein Angreifer kann ein bösartiges Objekt serialisieren und an Ihre Anwendung senden. Sobald Sie readObject() aufrufen, wurden die bösartigen Objekte bereits instanziiert. Vielleicht glauben Sie, dass solche Angriffe unmöglich sind, weil sich dafür eine anfällige Klasse in Ihrem Classpath befinden muss. Bedenken Sie jedoch, wie viele Klassen Ihr Classpath umfasst – Ihren eigenen Code, Java-Bibliotheken, Bibliotheken von Drittanbietern und Frameworks. Es ist sehr wahrscheinlich, dass sich darunter eine anfällige Klasse befindet.

Die Java-Serialisierung wird auch als „das Geschenk, das immer weitergibt“ bezeichnet, da sie im Laufe der Jahre zahlreiche Probleme verursacht hat. Oracle plant, die Java-Serialisierung im Rahmen vonProject Amber irgendwann zu entfernen. Das kann jedoch noch dauern und wird wahrscheinlich nicht in älteren Versionen behoben. Daher ist es ratsam, die Java-Serialisierung so weit wie möglich zu vermeiden. Wenn Sie Ihre Domänenentitäten serialisierbar machen müssen, implementieren Sie am besten eine eigene readObject()-Methode, wie unten gezeigt. Damit verhindern Sie die Deserialisierung.

private final void readObject(ObjectInputStream in) throws java.io.IOException {
   throw new java.io.IOException("Deserialized not allowed");
}

Wenn Sie einen InputStream selbst deserialisieren müssen, sollten Sie einen eingeschränkten ObjectsInputStream verwenden. Ein gutes Beispiel dafür ist der ValidatingObjectInputStream aus Apache Commons IO. Dieser ObjectInputStream prüft, ob das zu deserialisierende Objekt zulässig ist.

FileInputStream fileInput = new FileInputStream(fileName);
ValidatingObjectInputStream in = new ValidatingObjectInputStream(fileInput);
in.accept(Foo.class);

Foo foo_ = (Foo) in.readObject();

Probleme bei der Objekt-Deserialisierung treten nicht nur bei der Java-Serialisierung auf. Auch bei der Deserialisierung von JSON zu Java-Objekten können ähnliche Probleme auftreten. Ein Beispiel für ein solches Deserialisierungsproblem mit der Jackson-Bibliothek finden Sie im Blogbeitrag „Sicherheitslücke bei der Jackson-Deserialisierung“.

Weitere Informationen finden Sie in unserem Blogbeitrag Serialisierung und Deserialisierung in Java: Erklärung der Java-Deserialisierungs-Sicherheitslücke.

8. Verwenden Sie starke Verschlüsselungs- und Hashing-Algorithmen.

Wenn Sie vertrauliche Daten in Ihrem System speichern müssen, sollten Sie unbedingt für eine angemessene Verschlüsselung sorgen. Zunächst müssen Sie entscheiden, welche Art der Verschlüsselung Sie benötigen – zum Beispiel symmetrisch oder asymmetrisch. Außerdem sollten Sie festlegen, wie sicher sie sein muss. Eine stärkere Verschlüsselung benötigt mehr Zeit und CPU-Leistung. Am wichtigsten ist, dass Sie Verschlüsselungsalgorithmen nicht selbst implementieren müssen. Verschlüsselung ist schwierig, und eine vertrauenswürdige Bibliothek nimmt Ihnen diese Arbeit ab.

Wenn Sie beispielsweise Kreditkartendaten verschlüsseln möchten, benötigen Sie wahrscheinlich einen symmetrischen Algorithmus, da Sie die ursprüngliche Nummer wiederherstellen müssen. Nehmen wir an, Sie verwenden den Advanced Encryption Standard (AES), der derzeit der symmetrische Verschlüsselungsstandard für US-Bundesbehörden ist. Zum Ver- und Entschlüsseln müssen Sie sich nicht in die Low-Level-Java-Kryptografie vertiefen. Wir empfehlen Ihnen, eine Bibliothek zu verwenden, die Ihnen die aufwendige Arbeit abnimmt, zum Beispiel Google Tink.

<dependency>
   <groupId>com.google.crypto.tink</groupId>
   <artifactId>tink</artifactId>
   <version>1.3.0-rc1</version>
</dependency>

Unten finden Sie ein kurzes Beispiel für die Verwendung von Authenticated Encryption with Associated Data (AEAD) mit AES. Damit können Sie Klartext verschlüsseln und zugehörige Daten angeben, die authentifiziert, aber nicht verschlüsselt werden sollen.

private void run() throws GeneralSecurityException {
   AeadConfig.register();
   KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES256_GCM);

   String plaintext = "I want to break free!";
   String aad = "Queen";

   Aead aead = keysetHandle.getPrimitive(Aead.class);
   byte[] ciphertext = aead.encrypt(plaintext.getBytes(), aad.getBytes());
   String encr = Base64.getEncoder().encodeToString(ciphertext);
   System.out.println(encr);

   byte[] decrypted = aead.decrypt(Base64.getDecoder().decode(encr), aad.getBytes());
   String decr = new String(decrypted);
   System.out.println(decr);
}

Für Passwörter ist die Verwendung eines starken kryptografischen Hashing-Algorithmus sicherer, da Sie die ursprünglichen Passwörter nicht wiederherstellen, sondern nur die Hashes vergleichen müssen. Laut dem OWASP Password Cheat Sheet sind Argon2 und BCrypt derzeit die besten Hashing-Algorithmen für Passwörter. Für Legacy-Systeme kann bis zu einem gewissen Grad Scrypt verwendet werden. Alle drei sind kryptografische Hashes (Einwegfunktionen) und rechenintensive Algorithmen, deren Ausführung viel Zeit in Anspruch nimmt. Genau das ist erwünscht, denn dadurch dauern Brute-Force-Angriffe sehr lange.

Spring Security bietet hervorragende Unterstützung für eine Vielzahl von Algorithmen. Verwenden Sie zum Hashen von Passwörtern die Klassen Argon2PasswordEncoder und BCryptPasswordEncoder, die Spring Security 5.0 dafür bereitstellt.

Ein heute starker Verschlüsselungsalgorithmus kann in einem Jahr bereits schwach sein. Deshalb sollte die Verschlüsselung regelmäßig überprüft werden, damit Sie für die jeweilige Aufgabe den richtigen Algorithmus verwenden. Nutzen Sie geprüfte Security-Bibliotheken für diese Aufgaben und halten Sie Ihre Bibliotheken auf dem neuesten Stand.

9. Aktivieren Sie den Java Security Manager

Standardmäßig unterliegt ein Java-Prozess keinen Einschränkungen. Er kann auf verschiedenste Ressourcen zugreifen, etwa auf das Dateisystem, das Netzwerk und externe Prozesse. Es gibt jedoch einen Mechanismus, der all diese Berechtigungen steuert: den Java Security Manager. Standardmäßig ist der Java Security Manager nicht aktiviert, und die JVM hat uneingeschränkte Kontrolle über den Rechner. Auch wenn die JVM bestimmte Systembereiche wahrscheinlich nicht aufrufen soll, kann sie darauf zugreifen. Noch wichtiger ist, dass Java APIs bereitstellt, mit denen sich schädliche und unerwartete Aktionen ausführen lassen.

Am beunruhigendsten finde ich die Attach API. Mit dieser API können Sie eine Verbindung zu anderen laufenden JVMs herstellen und diese steuern. Wenn Sie Zugriff auf den Rechner haben, lässt sich beispielsweise der Bytecode einer laufenden JVM recht einfach ändern. Dieser Blogbeitrag von Nicolas Frankel zeigt, wie das funktioniert.

Der Java Security Manager lässt sich leicht aktivieren. Starten Sie Java mit einem zusätzlichen Parameter, um den Security Manager mit der Standardrichtlinie zu aktivieren: java -Djava.security.manager.

Die Standardrichtlinie passt jedoch wahrscheinlich nicht vollständig zu den Anforderungen Ihres Systems. Möglicherweise müssen Sie eine eigene Richtlinie erstellen und der JVM übergeben. java -Djava.security.manager -Djava.security.policy==/foo/bar/custom.policy

Beachten Sie das doppelte Gleichheitszeichen – damit wird die Standardrichtlinie ersetzt. Bei einem einfachen Gleichheitszeichen wird die Standardrichtlinie um Ihre benutzerdefinierte Richtlinie ergänzt.

Weitere Informationen zu Berechtigungen im JDK und zum Schreiben von Richtliniendateien finden Sie in der offiziellen Java-Dokumentation.

Hinweis:Seit der Veröffentlichung von Java 17 ist der Security Manager aufgrund der Implementierung von JEP 415 als „deprecated“ gekennzeichnet. In Java 17 ist er dennoch voll funktionsfähig. Derzeit verwendet die Mehrheit der Java-Entwickler in der Produktion entweder Java 8 oder Java 11. Das bedeutet, dass der Security Manager in der Praxis trotz seiner zukünftigen Entfernung weiterhin ein nützlicher Mechanismus ist.

10. Zentralisieren Sie Logging und Monitoring

Bei Sicherheit geht es nicht nur um Prävention. Sie müssen auch erkennen können, wenn etwas schiefläuft, um entsprechend zu handeln. Welche Logging-Bibliothek Sie verwenden, ist dabei weniger wichtig. Entscheidend ist, dass Sie umfangreich protokollieren, denn unzureichendes Logging ist laut OWASP Top 10 nach wie vor ein großes Problem. Grundsätzlich sollte jedes Ereignis, das geprüft werden könnte, protokolliert werden. Ausnahmen, Anmeldungen und fehlgeschlagene Anmeldungen sind offensichtliche Beispiele. Wahrscheinlich sollten Sie aber auch jede eingehende Anfrage samt Herkunft protokollieren. So wissen Sie zumindest, was wann und wie passiert ist, falls Ihr System angegriffen wird.

Es empfiehlt sich, die Protokollierung zentral zu bündeln. Wenn Sie Log4j oder logback verwenden, lässt sich das beispielsweise recht einfach an einen zentralen Elastic Stack anbinden. Mit Tools wie Kibana können Sie auf die Protokolle aller Server und Systeme zugreifen und sie für Untersuchungen durchsuchen.

Neben dem Logging sollten Sie Ihre Systeme aktiv überwachen und die Messwerte zentral und leicht zugänglich speichern. CPU-Spitzen oder eine enorme Last von einer einzelnen IP-Adresse können auf ein Problem oder einen Angriff hindeuten. Kombinieren Sie zentrales Logging und Echtzeit-Monitoring mit Benachrichtigungen, damit Sie bei ungewöhnlichen Ereignissen alarmiert werden.

Ein Zurücksetzen des Admin-Passworts, der Zugriff auf einen internen Server von einer externen IP-Adresse oder ein URL-Parameter wie ‘UNION’ sind nur einige Hinweise darauf, dass etwas nicht stimmt. Wenn Sie bei solchen Problemen die richtigen Warnmeldungen erhalten und nachvollziehen können, was tatsächlich passiert ist, können Sie größere Schäden wahrscheinlich verhindern und die Sicherheitslücke rechtzeitig beheben.

FAQ

Was bedeutet Java-Sicherheit?

Java-Sicherheit umfasst die Maßnahmen, die Java-Entwickler ergreifen, um zu verhindern, dass böswillige Nutzer eine Anwendung kompromittieren. Mit starkem und sicherem Java-Code schützen Entwickler die Vertraulichkeit, Integrität und Verfügbarkeit der Anwendung und der Daten.

Stellt Java ein Sicherheitsrisiko dar?

Java muss kein Sicherheitsrisiko darstellen. Wenn Sie Java ordnungsgemäß aktualisieren, nur die benötigten Module verwenden und Ihre Anwendungen mit einem sicherheitsorientierten Ansatz entwickeln, können Sie das Risiko minimieren. Dieses Cheat Sheet hilft Ihnen dabei, Sicherheitslücken in den Java-Anwendungen zu vermeiden, die Sie entwickeln.

Wo befindet sich die Java-Sicherheitsdatei?

Die Datei java.security befindet sich in der Java Runtime Environment (JRE) und enthält die standardmäßigen Sicherheitseigenschaften. Bei Java 8 und älteren Versionen finden Sie die Datei unter $JAVA_HOME/jre/lib/security. In neueren Java-Versionen liegt sie unter $JAVA_HOME/conf/security.

Starten Sie mit Capture the Flag

Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.