Sicherheit bei JAVA-Anwendung mit SQL

Um ein wenig wenig in Übung zu bleiben schreibe ich aktuell eine Client/Server Anwendung in JAVA inkl. MySQL-Anbindung.

Das Thema Sicherheit soll dabei natürlich nicht vernachlässigt werden, allerdings bin ich mir hier über bestimmte Eigenheiten von JAVA nicht so ganz sicher.

Die DB wird hauptsächlich als Benutzerverwaltung und Rechteverwaltung genutzt (zumindest derzeit noch, mal gucken was noch so kommt ;)), so dass die Benutzer derzeit auch noch gar nicht so viele Eingabemöglichkeiten haben.

Als ersten Schritt ist die Anwendung natürlich so geschrieben, dass ausschließlich der Server mit der DB kommuniziert, das sollte eine Selbstverständlichkeit sein, denke ich ;)

Nun muss ich mich aber ja auch um SQL-Injektions kümmern.

Ich habe aktuell 3 Eingabefelder, den Benutzernamen, das Passwort und eine Angabe zu einem Bereich (als String).

Das Passwortfeld wird noch vor der Übertragung vom Client zum Server gehasht, so dass dieses Feld wohl eher nicht anfällig sein dürfte, aber natürlich die anderen beiden.

Die DB-Anbindung habe ich mit einem scheinbar ganz guten Tutorial gemacht, denn dieses hat direkt PreparedStatements verwendet. Habe jetzt nachträglich herausgefunden, dass das auch die empfohlene Variante ist.
Derzeit baue ich meine Variablen aber noch direkt in das Statement ein, also etwa so:
Code:
PreparedStatement pstmt = con.prepareStatement("SELECT spalte1 FROM tabelle WHERE spalte2 =" + Stringvariable + ");"
anstatt
Code:
PreparedStatement pstmt = con.prepareStatement("SELECT spalte1 FROM tabelle WHERE spalte2 = ?");
pstmt.setString(1, Stringvariable);

Ist hier mit der Funktion setString() letztendlich ein Unterschied zu meiner Variante, da diese Funktion irgendetwas ausfiltert bzw. escaped oder sind beide Varianten äquivalent und ich muss mich noch selber um ein ausfiltern/escapen von ungewollten Zeichen kümmern?
Oder bin ich mit den PreparedStatements bereits gegen Injektions abgesichert (kann ich mir eigentlich nicht vorstellen)?

Habe ich hier noch andere Punkte übersehen, auf die ich unbedingt achten müsste?
 
prepared statements sind daher empfohlen, da du daten und abfrage trennen kannst ... leider kann dich das konzept dazu nicht zwingen ...

du solltest auf keinen fall mehr selbst die variablen in einen querystring schreiben, sondern dies in jedem fall von der query engine durchführen lassen ...

was andere sicherheitsaspekte anbelangt, hängt das wohl maßgeblich von dem ab was der rest des programms tun soll ... code nachladen wäre so eine typische problematik mit der ich mich demnächst mal beschäftigen sollte ... allerdings eher in c#
 
prepared statements sind daher empfohlen, da du daten und abfrage trennen kannst ... leider kann dich das konzept dazu nicht zwingen ...

du solltest auf keinen fall mehr selbst die variablen in einen querystring schreiben, sondern dies in jedem fall von der query engine durchführen lassen ...
Das habe ich mir schon fast gedacht, diesen Punkt hatte das Tutorial dann leider nicht mehr erwähnt :|

Ob durch die setString()-Funktion ein String nun aber escaped wird oder nichts damit gemacht wird, ist weiterhin offen und das ist ja doch ein sehr wichtiger Punkt, um keine Angriffsfläche zu bieten.
 
vom prinzip her ist es eine black box die dafür sorgt, dass deine daten auch daten bleiben ...

in den gänigen implementierungen wird an dieser stelle entweder das escapen vorbereitet (durchgeführt wirds erst wenn die query ausgelößt wird), oder für die daten wird ein entsprechendes handling mit dem dbms vereinbart, das die daten definitiv als solche kennzeichnet (ich meine mal was zu mssql gelesen zu haben was zu betreffender query erst den executionplan aufbaut, oder aus dem cache holt, und dann wirklich erst auf dieser ebene platzhalter ersetzt) ... wie der mechanismus auch im einzelfall implementiert ist, ist für die benutzung egal
 
Das heißt also, dass ich auf diese Weise dann bereits eine passende Absicherung habe und nicht noch irgendwie selber die Eingabe verarbeiten muss, richtig?

Du hast natürlich recht, dass es für mich letztendlich egal sein kann, wie das System das intern macht, nur finde ich die Doku hier zu wenig aussagekräftig um abschätzen zu können, ob die Klasse sich bereits um eine Absicherung der Eingaben kümmert oder ob man das selber machen muss. Daher ja auch überhaupt nur die Frage
 
alle prepared statement konzepte die ich bislang gesehen habe gehen davon aus dass du mit dem escapen der eingaben nichts mehr zu tun hast ... sofern du die query engine die parameter setzen lässt und das nicht selbst tust
 
Ja, bei Prepared Statements, werden alle Daten, die vorher mit "?" als Platzhalter gesetzt werden, direkt an die Datenbank gegeben. Ein Escaping ist nicht mehr nötig (und auch nicht sinnvoll), da die Daten den SQL-Parser gar nicht mehr durchlaufen.
Wenn du Prepared Statements verwendest und alle dynamische Daten über Platzhalter und setXYZ() einpflegst, ist eine SQL-Injection nach meiner Kenntniss nicht mehr möglich.

mfg, metax.
 
Man sollte bedenken, dass es ziemlich aufwaendig ist ein Statement zu parsen. PreparedStatements haben den Vorteil, dass sie einmalig auf Syntax geprueft werden muessen - Anschliessend nutzt man das Objekt weiter.

Code:
PreparedStatement pstmt = con.prepareStatement("SELECT spalte1  FROM tabelle WHERE spalte2 =" + Stringvariable + ");"
ist also ziemlich unsinnig.
Wenn, dann sollte man an dieser Stelle "normale" Statements nutzen.


Code:
PreparedStatement pstmt = con.prepareStatement("SELECT spalte1 FROM tabelle WHERE spalte2 = ?"); 
pstmt.setString(1, Stringvariable);
So sollte es schon wohl eher aussehen. Allerdings muss man darauf achten, dass die PreparedStatement-Objekte nicht zerstoert werden. Also irgendwie als Member- oder gar Static-Variable hinterlegen.

Factories eignen sich imho ganz gut zur Organisation von Queries.
 
Zurück
Oben