SQL Injection

In diesem Blogpost geht es um SQL Injection. SQL Injection ist etwas, von dem sich jede Webapplikation schützen muss, weil die basics es sehr einfach zu erlernen sind.

Was ist SQL Injection

Bevor man SQL Injection versucht zu verstehen, muss man zuerst logischerweise wissen, was SQL ist. SQL (Structured Query Language) ist eine deklarative Programmiersprache, die einem erlaubt, mit Datenbanken zu interagieren. Datenbanken werden in modernen Webapplikationen verwendet, um Daten zu verwalten und dynamische Inhalte für die Benutzer anzuzeigen. Heisst, die Datenbanken haben Daten und SQL sagt, was mit den Daten gemacht werden soll. Nun haben wir SQL Injection. Mit SQL Injection kann man die Befehle, die eine Webapplikation dem Datenbank gibt, manipulieren. Die Webapplikation wird somit von fremde Angriffe kompromittiert. Somit kann der Angreifer Zugang zu sensiblen Daten erhalten und sie auslesen, verändern oder sogar löschen. Sowas will man als Entwickler einer Webapplikation natürlich nicht, weshalb der Schutz vor SQL Injections für einen Entwickler immer oberste Priorität. Die SQL Injection gehört zu den zehn kritischsten Sicherheitsrisiken für Webanwendungen von OWASP. 

Es gibt Programmiersprachen, von denen manche sehr sensibel von SQL Injection sind und manche eher weniger. Einer der bekannteste Programmiersprache, die sensibel ist, ist PHP. PHP wird sehr oft verwendet, weil es simpel ist und man sehr effizient ist. Man kann den Code einfach in eine Textdatei schreiben, es in einem Webserver hochladen und es wird einfach funktionieren. Viele Applikationen wurden früher mit PHP programmiert, einer der bekanntesten davon war Facebook und WordPress ist immer noch mit PHP programmiert. Doch es hat viele Lücken für SQL Injection, die man als PHP Programmierer unbedingt berücksichtigen muss. PHP ist natürlich nicht die einzige Sprache, doch wir nehmen es einfach als Beispiel. 

Wie geht eine SQL Injection?

Wenn man eine Webapplikation vor sich hat, die durch Benutzereingaben die Datenbank aufruft und SQL Befehle gibt, kann man ganz einfach eine SQL Injection probieren. Beispielsweise hat eine Webapplikation ein typischen Anmeldeformular mit Benutzername und Passwort. Durch die eingereichten Daten fragt man danach die Datenbank ab, ob der Benutzer existiert und das Passwort richtig eingegeben hat. Somit kann sich der Benutzer authentifizieren und ist als Benutzer (bsp. Tom) angemeldet, wo er seine Daten hat. Man kann sich die SQL Abfrage so vorstellen:

Das Passwort wäre üblicherweise gehashed, aber das ignorieren wir hier mal.

Die Abfrage in PHP wird wie folgt definiert:

Nun kommt einer und gibt im Feld username den Wert “admin’;– ” ein. Als Passwort tippt die Person einfach irgendwas auf die Tastatur. Die SQL Abfrage wird dann wie folgt aussehen:

Ein Kommentar in SQL beginnt mit doppelten Strichen (-). Die Eingabe “admin’;– ” hat also den string mit beendet, die Abfrage mit einem Semikolon beendet und der Datenbank mitgeteilt, dass alles was danach kommt als Kommentar angesehen werden soll und nicht zu berücksichtigen. Somit sucht man nicht mehr den Benutzer “admin” mit den Passwort “mypassword”, sondern nur den Benutzer “admin”, ohne überhaupt das Passwort zu kennen. Man kann sich somit, falls es den Benutzer admin gibt, einfach als Administrator anmelden und volle Zugriff auf die Webapplikation haben. Es gibt selbstverständlich auch weitere Arten, eine SQL Injection durchzuführen, wie zum Beispiel “‘ or 1=1;– ” als Passwort einzugeben. Man muss auch seine Befehle nach dem ersten SELECT Statement nicht abschliessen. Man kann auch einfach die ganze Tabelle fallen lassen / löschen mit “‘ or 1=1; DROP TABLE user;– ”. 

Eine Karikatur zur SQL Injection
Devhumor - humor for developers

Wie schützt man sich vor SQL Injections?

Es wäre natürlich furchtbar, wenn man sich vor solche einfache Befehlen nicht schützen kann. Deshalb gibt es verschiedene Techniken, sich vor SQL Injections zu schützen.

Escape Benutzereingaben

Es ist schwer festzustellen, ob eine Benutzereingabe bösartig ist oder nicht. Die Sonderzeichen in einer Benutzereingabe sollen daher am besten vermieden werden.

In PHP (Bis Version 7.0) gibt es die Funktion mysql_real_escape_string(string). Mit dieser Funktion wird der Text auf Escape Zeichen geprüft und setzt vor ihnen ein backslash \, damit die Datenbank es als normalen Text ansieht und nicht als ein spezielles Zeichen. Aus “‘ or 1=1;– ” wird somit 

\‘ or 1=1;– ”. 

Kleiner Fun Fact: Es gab früher die Funktion mysql_escape_string(string), doch sie Funktionierte nicht richtig. Die Funktion konnte jedoch nicht abgeändert werden, weshalb man sich entschieden hat eine neue Funktion zu machen und das Wort “real” im Funktionsnamen rein zu packen, damit man weiss, welche man benutzen soll. So ist mysql_real_escape_string entstanden.

Die Technik mit den Escape Benutzereingaben kann zwar funktionieren, ist aber nicht die beste Lösung, da es nur die Escape Zeichen verhindert und nicht Operators wie “OR” oder “AND” etc. 

Prepared Statements

Die bessere Lösung sich vor SQL Injections zu schützen sind prepared statements. Mit prepared statements definiert man einfach die normale SQL Anweisung, doch an den Stellen, wo eine Benutzereingabe kommt, setzt man stattdessen ein Fragezeichen hin. Das ganze sieht so aus:

An den Stellen wo das Fragezeichen ist kommen nun die Benutzereingaben. Hier ist es speziell, dass die Werte von den Fragezeichen (Also die Benutzereingaben die dort hinkommen) nur als ganz normaler Text ohne Rücksicht auf irgendwelche Spezialzeichen oder Sonstiges angesehen werden. Man sagt der Datenbank, dass egal was dort reinkommt man es als Text und nichts weiter sehen soll. Das ist auf jeden Fall eine gute Lösung gegen SQL Injection, doch nur weil man sie ab jetzt benutzt, heißt das nicht, dass man völlig sicher von SQL Injections ist.