Wie Sie Hackern das Knacken Ihres Java-Codes erschweren: SQL-Injection und XSS unter der Lupe
\n\nStellen Sie sich vor: Sie haben eine perfekte Webanwendung in Java geschrieben. Schönes Interface, schnelle Logik, saubere Architektur. Sie laden sie auf den Server hoch, brühen sich einen Tee auf und... eine Stunde später erhalten Sie die Nachricht, dass die Datenbank gelöscht wurde und auf der Startseite ein frecher ASCII-Art prangt. Eine bekannte Geschichte? Leider für viele Entwickler – ja.
\n\nDie beiden häufigsten und gefährlichsten Schwachstellen von Webanwendungen – SQL-Injection und Cross-Site-Scripting (XSS) – rauben jährlich Administratoren tausender Websites den Schlaf. Und Java ist trotz seiner Strenge keine Ausnahme. Aber es gibt auch eine gute Nachricht: Der Schutz davor ist machbar. Und sogar nicht besonders schwierig.
\n\nIn diesem Artikel analysieren wir, wie genau Angreifer Java-Anwendungen attackieren, und vor allem – wie Sie mit bewährten Werkzeugen und richtigen Codierungsgewohnheiten einen zuverlässigen Schutzschild aufbauen. Schnallen Sie sich an: Es wird viel Code, Lifehacks und ein Minimum an Fülltext geben.
\n\nSQL-Injection: Wenn der Benutzer zum Programmierer wird
\n\nWas ist das und warum funktioniert es?
\n\nSQL-Injection ist eine Angriffstechnik, bei der ein Angreifer schädlichen SQL-Code über Benutzereingaben in eine Abfrage einschleust. Wenn die Anwendung gedankenlos Strings zusammenklebt, kann der Angreifer auf fremde Daten zugreifen, Tabellen löschen oder sogar die Kontrolle über den Datenbankserver übernehmen.
\n\nEin klassisches Beispiel für schlechten Java-Code:
\n\nString userInput = request.getParameter("username");\nString query = "SELECT * FROM users WHERE username = '" + userInput + "'";\nStatement stmt = connection.createStatement();\nResultSet rs = stmt.executeQuery(query);\n\nWas passiert, wenn der Benutzer eingibt: admin' OR '1'='1? Die Abfrage wird zu:
SELECT * FROM users WHERE username = 'admin' OR '1'='1'\n\nDie Bedingung '1'='1' ist immer wahr. Herzlichen Glückwunsch: Der Angreifer hat sich gerade als Administrator angemeldet, ohne das Passwort zu kennen. Und wenn er '; DROP TABLE users; -- eingibt – dann ist das Kind in den Brunnen gefallen.
Wie man sich schützt: PreparedStatement – Ihr Schutzschild
\n\nDie Regel Nummer eins in der Java-Anwendungssicherheit: niemals Benutzereingaben mit SQL-Abfragen verketten. Verwenden Sie parametrisierte Abfragen mit PreparedStatement.
So sollte sicherer Code aussehen:
\n\nString userInput = request.getParameter("username");\nString query = "SELECT * FROM users WHERE username = ?";\nPreparedStatement pstmt = connection.prepareStatement(query);\npstmt.setString(1, userInput);\nResultSet rs = pstmt.executeQuery();\n\nWas ist hier passiert? Die Datenbank erhält die Abfrage und die Daten getrennt. Selbst wenn userInput bösartigen SQL-Code enthält, wird er als normale Zeichenkette und nicht als Befehl interpretiert. PreparedStatement maskiert Sonderzeichen automatisch. Dies ist die erste und wichtigste Verteidigungslinie.
Zusätzliche Maßnahmen: Gespeicherte Prozeduren und Validierung
\n\nNeben PreparedStatement sollten Sie Folgendes verwenden:
- \n
- Gespeicherte Prozeduren – der Aufruf einer Prozedur über
CallableStatementtrennt ebenfalls Code von Daten. \n - Whitelists – wenn Sie einen Tabellen- oder Spaltennamen einsetzen müssen (was selten vorkommt), nehmen Sie ihn niemals aus der Benutzereingabe. Verwenden Sie enum oder streng definierte Konstanten. \n
- Eingabevalidierung – prüfen Sie, ob eine E-Mail wie eine E-Mail aussieht und eine Zahl eine Zahl ist. Aber denken Sie daran: Validierung ist eine zusätzliche Schicht, kein Ersatz für
PreparedStatement. \n
Beispiel für die sichere Arbeit mit dynamischen Tabellennamen:
\n\npublic enum TableName {\n USERS, PRODUCTS, ORDERS\n}\n\npublic void queryTable(TableName table) {\n String que