Keine Angst vor Injection Autor Carsten Czarski, ORACLE Deutschland GmbH Injection ist ein viel diskutierter Begriff, wenn es um die Entwicklung von Datenbankgestützten Web-Anwendungen geht. Darunter versteht man das Aushebeln von Sicherheitsregeln bzw. die Manipulation von Daten durch das Einschleusen (Injizieren) von veränderten -Anweisungen. Injection ist unabhängig von der verwendeten Technologie. Ob also Java/J2EE, PHP,.NET oder eine andere Technik verwendet wird Injection ist stets ein Thema für den Entwickler. Selbst wenn Injection hauptsächlich im Zusammenhang mit Web-Anwendungen diskutiert wird, ist es nicht nur auf diese beschränkt. Abbildung 1 Erfolgreicher -Injection-Angriff Abbildung 1 zeigt einen erfolgreichen -Injection-Angriff auf ein PHP-Skript. Zusätzlich zu den Mitarbeitern wird der Inhalt der Data Dictionary View USER_OBJECTS angezeigt man kann sich also bequem im Datenbank- Schema umschauen. Dieser Artikel zeigt, wann Anwendungen für Injection anfällig sind, warum das Thema gerade bei Web- Anwendungen im Fokus steht und wie man sich als Entwickler schützen kann. Die gute Nachricht dabei ist Beachtet man einige Grundsätze, so lässt sich die Anfälligkeit einer Anwendung für -Injection-Angriffe erheblich verringern. Injection und "dynamisches" Die Gefahr von Injection entsteht, wenn -Anweisungen in der Anwendung dynamisch durch String-Verkettung zusammengesetzt werden also "dynamisches" verwendet wird. Während PreCompiler wie Pro*C oder J ebenso wie PL/ einen Unterschied zwischen statischem und dynamischem machen, kennen PHP-,.NET- oder JDBC-Programmierer einen solchen Unterschied nicht schließlich wird hier jedes -Kommando als String repräsentiert und an die Datenbank gesendet. Im PHP-,.NET- oder JDBC-Umfeld ist im Grunde genommen also jedes dynamisch. Das Grundprinzip von Injection Im Bereich der Web-Anwendungen müssen zusätzlich die Wege betrachtet werden, wie Eingaben und Parameter vom Browser an die Anwendung übermittelt werden per URL per Formular und der HTTP-Methode POST per Cookie Bei keinem dieser Wege kann der Entwickler einer Applikation die Inhalte kontrollieren, die dieser übermittelt wer- 20
Security den. Insofern sollte man als Entwickler einer Web-Anwendung stets misstrauisch sein gegenüber "allem, was vom Browser kommt". Bewegt man sich durch eine Web- Anwendung, so findet man recht häufig URL s nach folgendem Schema http//app.firma.de/app/test.jsp?custid=9 Listing 1 URL-Beispiel für eine Web-Anwendung Hier ist leicht erkennbar, dass im Hintergrund eine Java-Server-Page arbeitet diese bekommt den Wert 9 als custid übergeben. Mit dieser Information wird nun wahrscheinlich eine Datenbank-Tabelle abgefragt. Die Ergebnisse werden dann dem Anwender als Web-Seite präsentiert. In vielen Fällen, in denen die HTTP-Methode POST oder ein Cookie verwendet wird, sind die Variablen und Inhalte nicht aus der URL erkennbar. Dies bedeutet jedoch nicht, dass sich der Entwickler in Sicherheit wiegen kann. Die Namen der Variablen lassen sich leicht ermitteln, indem man sich im Browser den Seitenquelltext anzeigen lässt. Die Erstellung eines eigenen HTML-Formulars zur Übermittlung der gewünschten Werte ist dann ein Leichtes. Angenommen, die genannte JSP zeigt die vorhandenen Konten eines Kunden an. Listing 2 zeigt als Beispiel etwas Java-Code, wie er in der JSP vorkommen könnte. Mit den Kommentarzeichen (--) wird ein eventuell nachfolgender Rest des -Kommandos einfach auskommentiert alle weiteren Einschränkungen fallen weg. Die Abfrage liefert nun die ganze Tabelle zurück. So funktioniert Injection Durch Veränderung der URL wird die Struktur und damit der Sinn des -Kommandos verändert. Denkt man noch etwas weiter, so könnte man auch ein UNION ALL anhängen und damit alle Objekte im Datenbank-Schema selektieren. Injection kann auch beim Aufruf einer PL/- Stored-Procedure auftreten. Angenommen, die im Folgenden aufgerufene Prozedur myproc nimmt einen Parameter vom Typ VARCHAR2 entgegen con.preparecall("{myproc("+sid+")}"); ctmt.execute(); Listing 5 Anfälliger Code für Stored Procedures Obwohl in Listing 5 sogar die JDBC-Syntax für Stored-Procedures verwendet, ist der Code anfällig für Injection, denn auch hier findet Stringverkettung statt und der HTTP- Parameter id wird ohne weitere Prüfung übernommen. String ssql; String sid; String smanid = "MAN01"; ssql = "select name, vorname " + "where id = " + sid + " " + "and mandantid = " + smanid; stmt = con.createstatement(ssql); Listing 2 Beispielcode einer Web-Anwendung Der übergebene HTTP-Parameter custid wird mit der Methode request.getparameter() ausgelesen. Der Wert wird anschließend in die -Abfrage eingebaut und diese dann ausgeführt. Wird diese JSP nun mit einer geänderten URL /app/test.jsp?cust_id=9 or 1=1 -- Listing 3 Versuch eines -Injection-Angriffs aufgerufen, so ändert sich damit auch die -Abfrage. Select name, vorname from Kundentabelle Where id = 9 or 1=1 - and mandantid = 1 Listing 4 Injection ausgeführte -Abfrage 21
Übergibt man meintext'); execute immediate 'drop table MEINE_TAB'; myproc(1 Listing 6 Injection-Angriff auf Listing 5 so wird tatsächlich folgender Code ausgeführt con.preparecall("{ myproc('meintext'); execute immediate 'drop table '; myproc('1')}" ); cstmt.execute(); Listing 7 Tatsächlich ausgeführter PL/-Code Wie bereits oben erwähnt, ist das gleiche Beispiel auch bei Verwendung anderer Web-Technologien denkbar. Skript-Sprachen wie PHP oder Perl fordern vom Entwickler besondere Aufmerksamkeit, denn sie kennen keine Daten- Typen. Aus diesem Grund nehmen PHP- oder Perl-Entwickler typischerweise keine Umwandlung in numerische Daten-Typen vor, die einen gewissen Schutz vor - Injection-Angriffen bieten würde. Schutz durch Verwendung von Bind-Variablen Ein erster, genereller Ansatz zum Schutz vor -Injection- Angriffen ist die Verwendung von Bind-Variablen. Listing 8 Nutzung von Bind-Variablen in einer JSP PreparedStatement pstmt; ssql = "select name, vorname " + pstmt.setstring(1, sid); pstmt.setint(2, imandantid); con.preparecall("{myproc(?)}"); cstmt.setstring(1, sid); cstmt.execute(); Werden Bind-Variablen verwendet, so parst und interpretiert die Datenbank das -Kommando im ersten Schritt und erst danach findet die Ersetzung der Variablen durch ihre Inhalte statt. Damit ist es nicht mehr möglich, durch Änderungen an Parametern die Struktur und damit den Sinn der -Abfrage zu verändern ein UNION ALL kann nicht mehr untergeschoben werden. Nun können Bind-Variablen nicht immer verwendet werden. Sie sind nur in SELECT- und DML-Anweisungen möglich und dort nur als Parameter in der SELECT-Liste oder in der WHERE-Bedingung. Mit Bind-Variablen können Tabellen- oder Spalten-Namen niemals dynamisch gestaltet werden. Ist dies in der Anwendung gefordert, so muss mit Stringverkettung gearbeitet werden. scol = request.getparameter("showcol"); ssql = "select " + scol + " " + Listing 10 Dynamische Spaltenwahl Listing 10 zeigt den Java-Code, der dynamisch die anzuzeigende Spalte in einer -Abfrage setzt. Typische Anwendungsgebiete sind Web-Anwendungen, in denen der Anwender die Informationen selbst auswählen kann, die er sehen möchte. Anhand der ausgewählten Tabellenspalten stellt die Anwendung dann die -Abfrage zusammen. Auf den ersten Blick ist dies ungefährlich, denn durch Änderungen des HTTP-Parameters showcol kann ja nur die SELECT-Liste verändert werden. Übergibt man jedoch /app/test.jsp?showcol=null, null from dual union all (select -- so kann man eine solche JSP ebenfalls nutzen, um jede beliebige Tabelle abzufragen. In diesem Fall helfen Bind-Variablen nicht weiter, da sie nicht für Tabellen- oder Spaltennamen verwendet werden können. An der String-Verkettung zum Zusammensetzen der -Abfrage kommt der Entwickler hier nicht vorbei. Listing 9 Bind-Variablen beim Aufruf einer Prozedur Die Besonderheit der Bind-Variablen ist der Zeitpunkt, zu dem die Variable durch ihren Wert ersetzt wird. Bei einer einfachen String-Verkettung findet diese Ersetzung auf Anwendungsseite statt, bevor die Datenbank das - Kommando parsen und interpretieren kann. 22
Security Schutz durch Prüfen/Maskieren übergebener Werte Die einzige Lösung ist, die Objektnamen in der -Abfrage mit "Delimitern" einzugrenzen und die übergebenen Parameter vorher zu prüfen. So kann das aus Listing 10 auch wie folgt geschrieben werden scol = request.getparameter("showcol"); ssql = "select \"" +check(scol)+ "\" " + Listing 11 Dynamische Spaltenwahl mit Delimiter Objektnamen können in der Oracle-Datenbank mit doppelten Anführungszeichen umschlossen werden. Nebeneffekt ist, dass die Groß-/Kleinschreibung für Objektnamen nun relevant wird. Da die doppelten Anführungszeichen jedoch im -Injection-Angriff berücksichtigt werden könnten, müssen die Inhalte der verwendeten Variablen vorher geprüft werden. Dazu ist in diesem Beispiel die Java-Methode check() vorgesehen. public String check(string value) { return value.replaceall("\"",""); } Listing 12 Entfernen doppelter Anführungszeichen Mit diesen beiden Maßnahmen lassen sich -Injection- Angriffe zu großen Teilen verhindern. Alle Angriffe, die darauf zielen, andere Tabellen zu selektieren, können so effektiv abgewehrt werden. Zugriffsrechte direkt an den Daten hinterlegen Eine weitere, wirkungsvolle Maßnahme ist das Hinterlegen von Zugriffsregeln direkt in der Datenbank. Wird eine Tabelle, die Daten zu mehreren Mandanten enthält, beispielsweise durch Oracle Virtual Private Database (VPD) geschützt, so liefert selbst ein SELECT * from TABELLE nur die Daten zurück, die der gerade angemeldete Benutzer sehen darf ein -Injection-Angriff zielt also ins Leere. Fazit Injection ist bei allen Web-Technologien (Java,.NET, C/C++, PHP, ) möglich. Der Grund liegt allein im Zusammensetzen von -Anweisungen durch String-Verkettung, wobei Benutzereingaben bzw. HTTP-Parameter ohne weitere Prüfung übernommen werden. Deshalb ist auch der erfahrenste Entwickler nicht vor Injection gefeit. Hält man jedoch einige Grundsätze ein, so lässt sich das Risiko ganz erheblich reduzieren Wo es möglich ist, sollten Bind-Variablen genutzt werden. Wenn Bind-Variablen nicht möglich sind, sollten alle Werte, die die Applikation durch URL, Web-Formulare oder Cookies erhält, geprüft werden. Bei Datenbank-Objektnamen sollten doppelte Anführungszeichen entfernt werden. Ihr Partner für optimale Oracle-Lösungen Es gibt viele gute Gründe, sich für die msg systems ag zu entscheiden einer davon ist unsere enge Zusammenarbeit mit der Oracle Deutschland GmbH Als Oracle Certified Advantage Partner bieten wir Ihnen umfassendes Consulting und leistungsfähige Lösungen mit modernster Datenbank-Technologie. Real Application Clusters Oracle Application Server für Web-Anwendungen Oracle Collaboration Suite für Unified Messaging-Lösungen Lizenzberatung und Optimierung Oracle Recovery Manager (RMAN) Oracle FORMS-Migration Ein weiterer Grund ist unsere Partnerschaft mit der PITSS GmbH PITSS.CON ist das universelle Development-Tool für eine effiziente Analyse, Migration, Pflege und Weiterentwicklung von Oracle FORMS- Anwendungen. PITSS.CON ermöglicht Ihnen, auf die 3-tier Architektur umzusteigen und alle Chancen einer Webeinbindung für Ihr Unternehmen zu nutzen. Nicht umsonst wird dieses Tool auch offiziell von Oracle empfohlen und eingesetzt. Die msg systems ag ist der einzige Certified Implementation Partner und Certified Reseller Partner der PITSS GmbH in Deutschland. Wir unterstützen Sie bei der Planung, Installation und Einführung von Oracle-Produkten. Gerne übernehmen wir auch die Wartung Ihrer Datenbanken und Anwendungen. Die msg systems ag gehört zu den Top 25 IT-Beratungs- und Systemintegrationsunternehmen in Deutschland. Wir analysieren, gestalten und setzen um. Wir bieten Lösungen. msg systems ag Geschäftsstelle Berlin Tempelhofer Weg 64 12347 Berlin Tel. 030/66 06 70-0 oracle-competence@msg.de 23
Zugriffsrechte sollten so nahe wie möglich an den Tabellen hinterlegt werden. Eine Möglichkeit dafür ist Oracle Virtual Private Database (VPD). Es empfiehlt sich, den Anwendungscode, der -Anweisungen an die Datenbank sendet und keine Bind-Variablen verwendet, im Rahmen eines Code-Review von einer dritten Person auf -Injection-Probleme kontrollieren zu lassen. Hält man zudem die genannten Grundsätze ein, so kann man das Risiko für -Injection-Angriffe zwar nicht komplett ausschließen, aber zumindest stark reduzieren. Weitere Informationen AskTom "Defending and detecting injection" http//asktom.oracle.com/pls/ask/f?p=49508f4950 _P8_DISPLAYID23863706595353 Binding Variables in Oracle and PHP http//otn.oracle.com/pub/articles/oracle_php_ cookbook/ullman_bindings.html Schutz vor Injection für Oracle Application Express http//www.oracle.com/de/community/index_v34. html Oracle Virtual Private Database http//otn.oracle.com/deploy/security/db_security/ virtual-private-database/index.html Kontakt Carsten Czarski carsten.czarski@oracle.com 24