Framework gesucht gegen SQL-Injection

Hallo zusammen,

ich bin gerade etwas ratlos. Ich versuche mittels ESAPI Strings zu codieren um SQL-Injections zu vermeiden.

Erstmal kurz zum Aufbau und warum das nötig ist:

Es gibt einen Backend-Server der mittels RPC-Calls gesteuert wird. Dort gibt es unter anderem Methoden, die eine komplette Where-Klauseln erwarten und direkt an die Oracle-DB weiterreichen.

Dazu gibt es einen Client der sich, anhand gewählter Optionen in der GUI, diese Where-Klauseln zusammenstellt. (String-Konkatenation in if-Abfragen ob irgendeine Checkbox gecheckt ist)

Bisher ist der Client auf dem Ziel-Server installiert und wird bspw. mit Putty als X-Window(?) gestartet.

Jetzt soll dieser Client lokal auf den jeweiligen Rechnern laufen und sich gegen einen WebService verbinden. Diesen WebService darf ich gerade umsetzen und hab die Anforderung bekommen, SQL-Injection zu verhindern, da der WebService nicht nur mittels Client erreichbar sein soll. Auf Backend-Server und Client-Anwendung habe ich keinen Einfluss.

Bevor ich mir da jetzt selbst was zusammenbastel, hab ich nach Frameworks gesucht, die das können und hab OWASP ESAPI gefunden.
Laut: https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet#Oracle_Escaping scheint dies aber nur zu klappen, wenn man einzelne Werte damit codiert. Und nicht komplette Statements bzw. Where-Klauseln.

Hab ich da was übersehen oder gibt es da was anderes?

Ich werd nachher zu hause mal damit etwas rumspielen, vermute aber noch nicht das richtige gefunden zu haben.

Nur damit ich das richtig verstehe - ihr stringt euch komplette where clauses auf dem Client zusammen, und übergebt sie dem Server? Also schickt der client „where x = y and c = d“?

http://software-security.sans.org/developer-how-to/fix-sql-injection-in-java-using-prepared-callable-statement

Und sowas wie:

public void injectme(String wtf) { String query = wtf; PreparedStatement stmt = connection.prepareStatement(query); ResultSet rs = stmt.executeQuery(); } ....

nein

SQL-Injection und das Verhindern derselben sind ja keine Zaubertricks die man mal eben mit ja/ nein/ fertig behandeln kann,

für einzelne Werte ist das noch logisch klar: ein Wert kann man als Zahl oder Datum identifizierten oder sonst sicher zu einem String machen, alle internen Anführungszeichen escapen usw.,

aber wenn mehr kommt, wie von inv_zim etwa genannt “where x = y and c = d”, was soll dann mit diesem bereits höheren Block passieren?
niemand kann das gegen SQL-Injection sicher machen, niemand kann entscheiden was valides SQL ist welches bleiben muss, und was womöglich böse injected ist,

mit weiteren Hinweisen zum Aufbau mag es gehen, aber dann kann man ja vielleicht auch wieder getrennt übertragen, festes SQL (bzw. das schon im Server bekannt, nicht zu übertragen, sonst womöglich noch beeinflusst…) + Parameter

was genau gemeint ist, welche Abläufe, das vielleicht genau zu klären mit Beispielen,
wobei ich persönlich zu der Sache wahrscheinlich gar nichts konkretes sagen kann, nur solche Allgemeinweisheiten

bzw. Parameter im Statement benutzen

ähh doch. Wer mit Software zu tun hat, die auch nur ansatzweise sicherheitskritisch sein könnte kann sich hier etwas anlesen:

Um zu testen ist das auch ganz nett:

Ansonsten könnte ich einen unserer Workshops für Secure Coding empfehlen, dann lernen wir uns vll. kennen :wink:

danke für die Blumen :wink:

mit SQL

select user where name = x; und dazu x = "'Podolski' or money >1000"

ist es leicht was zu erreichen,

aber mit schon fertig erstellten SQL in früheren Schritt

select user where name = 'Podolski' or money >1000

kann niemand mehr aktuell entscheiden, was nun Injection ist oder was normales SQL ist, darum gings,
Parameter waren in Frage gestellt und höheres gemeint

wie wärs mit einem Workshop für allgemeine Lesekompetenz :wink:

Ich halte es da auch wie SlaterB.

Das System das du bauen sollst ist letztendlich auf SQL-Injection aufgebaut. Und das ganze gegenüber SQL-Injection abzusichern ist sogesehen absurd.

Quasi ein Türschloss das jeder ohne Schlüssel öffnen kann, aber dennoch gegenüber Einbrechern sicher ist.

Anstelle von money >1000 könnte auch ein true = true reinkommen oder ein Subselect auf diverse andere Tabellen oder Aufrufe von SP.

ja, das passiert so. keine Ahnung wer sich das ausgedacht hat, vermutlich wurden die Dinger einfach zu komplex und es war einfacher sich die Dinger selbst zusammen zu bauen als dafür ordentliche Methoden zu hinterlegen.

Allgemein:
ich hatte schon befürchtet das sowas nicht möglich ist, automatisiert zu erkennen bzw. zu verhindern. Dann werd ich dem Kunden sagen müssen, dass so nicht möglich ist und das besser im Backend abgefangen wird oder man eben generell das Vorgehenmit den Where-Klauseln überdenken sollte.

vom Client könnte ja eine Liste kommen, Feld-Name + Wert,

  • evtl. bisschen zusätzliches falls nicht reine OR- oder AND-Verknüpfung, und das dann noch modellierbar ist,

nur der Server baut zusammen, Werte gesichert (selber wenn ausreichend mutig, Extra-Framework oder etwa PreparedStatement bzw. Hibernate),
Feld-Namen auch nach Bekanntheit geprüft -> sicheres SQL

genausogut könnte der Client natürlich weiterhin das schicken was er schickt,
und ein Code im Server das neu zerlegen/ analysieren,
prüfen ob nur bekannte und erlaubte Felder abgefragt usw.,
aber das muss man dann selber manchen, dafür gibt es kein Framework

Ich sehe es so, wie die anderen hier. Um dieses kaputte Design gegen SQL-Injection abzusichern*, müsste man die möglichen Queries einschränken. Der Server müsste also die vom Client gewollten Queries kennen. Und um das umzusetzen, sollte man von SQL weggehen, weil sich das ansonsten nicht interpretieren lässt, ohne selbst eine SQL-Engine zu implementieren, welche die Queries wieder aufdröselt.

* eigentlich ist das gar keine SQL-Injection mehr, weil quasi beliebige Queries ausgeführt werden dürfen.

1 „Gefällt mir“

Das Problem ist, dass der Server unverändert bleiben soll und der Client halt nur den Umweg über den WebService nehmen soll anstatt direkt zum Backend-Server.

Andere Systeme, die den WebService nutzen sollen sind noch nicht bekannt.

Der Kunde wird sich dann eben damit zufrieden geben müssen, dass bei den SQL-Statements die gleiche “Sicherheit” wie vorher herrscht.

Wieviel Aufwand ist denn erlaubt?

Einfach eine ANTLR Grammatik nehmen, den WHERE-Teil rausschälen und den eingegebenen String einfach mal parsen. Dann neu Zusammenbauen unter der Annahme, dass es sich nur um ziemlich einfache Ausdrücke handelt.

Vielleicht reicht aber auch schon eine einfache Ausdruckssprache mit

-Spaltennamen als literalen
-AND OR NOT
-Klammern
-<,>,<=,>=
-IN, NOT IN
-IS NULL
und ein paar Funktionen. (vgl. http://stackoverflow.com/questions/25096713/parser-lexer-logical-expression)

Ein group-By ist ja nicht möglich, du filterst ja nur reine Zeilen.

Ich hab mal ein Beispiel rausgesucht, dass mir zur Verfügung gestellt wurde:

StringBuilder whereString = new StringBuilder();
        whereString.append("where (");
            whereString.append("(ABC_GUELTIG_BIS is NULL");
            whereString.append(" or ABC_GUELTIG_BIS>sysdate)");
            whereString.append("and not exists (");
                whereString.append("select * from EFG");
                whereString.append(" where EFG_TAB_NAME='ABC' and EFG_TAB_ID=ABC_ID and EFG_STATUS='SUC'");
            whereString.append(")");
            whereString.append("and ABC_EFG != 'F'");
        whereString.append(")");
        whereString.append("or exists(");
            whereString.append("Select XYZ_ABC_ID from XYZ where");
                whereString.append("(XYZ_GUELTIG_BIS is NULL");
                whereString.append(" or XYZ_GUELTIG_BIS>sysdate)");
                whereString.append("and not exists (");
                    whereString.append("select * from EFG");
                    whereString.append(" where EFG_TAB_NAME='XYZ' and EFG_TAB_ID=XYZ_ID and EFG_STATUS='SUC'");
                whereString.append(")");
                whereString.append("and XYZ_EFG != 'F'");
                whereString.append("and XYZ_ABC_ID=ABC_ID");
            whereString.append(")");

Das wird zwar ohne if-Abfragen zusammen gebaut, zeigt aber ganz gut die Komplexität

ok, subselects sind natürlich hart an der Grenze :slight_smile:

dann müsst ihr eben damit leben, dass man sql-injection hier nicht verhindern kann, weil es quasi zu den requirements gehört