Mit der Verschlüsselung in SQL Server soll die Absicherung von Daten gegen unbefugte Zugriffe kein Problem mehr sein.
SQL Server verfügt über eingebaute Verschlüsselungsmechanismen zum Schutz unterschiedlicher Arten vertraulicher Daten. In einigen Fällen ist die Verschlüsselung für den Anwender vollständig transparent: Daten werden beim Speichern verschlüsselt und beim Zugriff automatisch wieder entschlüsselt. In anderen Fällen kann man selbst entscheiden, ob die Daten verschlüsselt werden sollen oder nicht. SQL Server kann die folgenden Komponenten verschlüsseln:
- Passwörter
- Definitionen gespeicherter Prozeduren, Ansichten, Trigger, benutzerdefinierte Funktionen, Defaultwerte und Regeln
- Daten, die zwischen Server und Client ausgetauscht werden
Passwort-Verschlüsselung
SQL Server verschlüsselt automatisch alle Passwörter, die man für Logins und Anwendungsrollen festlegt. Selbst der direkte Blick in die Systemtabellen der Master-Datenbank enthüllt keine Passwörter. Diese Funktion muss man nicht erst aktivieren – im Gegenteil, man kann sie nicht deaktivieren.
Definitions-Verschlüsselung
In einigen Fällen enthalten die Definitionen von Objekten Informationen, die man nicht unbedingt mit anderen Anwendern teilen möchte. So könnte eine gespeicherte Prozedur z. B. vertrauliche Geschäftslogik enthalten, die nicht für alle Benutzer zugänglich sein sollte, selbst wenn diese die Systemtabellen öffnen und die Objekt-Definitionen anschauen können. Aus diesem Grund ermöglicht SQL Server die Verschlüsselung von Objekt-Definitionen, wenn man ein Objekt erstellt. Zur Verschlüsselung einer gespeicherten Prozedur verwendet man die Anweisung CREATE PROCEDURE wie folgt:
Interessant ist hier nur das optionale WITH-Argument: Man kann entweder RECOMPILE oder ENCRYPTION oder beide gemeinsam verwenden. Das Schlüsselwort ENCRYPTION verhindert, dass SQL Server die Prozedur öffentlich zugänglich macht. Daher wird die gespeicherte Systemprozedur sp_helptext ignoriert, wenn ENCRYPTION aktiviert ist. Diese spezielle gespeicherte Prozedur zeigt den zur Erstellung der Prozedur verwendeten Text an. Falls man die Verschlüsselung einmal deaktivieren will, kann man ALTER PROCEDURE zur Neuerstellung der gespeicherten Prozedur verwenden, wobei man die WITH ENCRYPTION-Klausel weglässt. SQL Server unterstützt auch die Verschlüsselung von Daten, die zwischen dem Server und einem Client im Netzwerk übertragen werden. Dies ist besonders nützlich, wenn sich der Client im öffentlich zugänglichen Internet befindet und man befürchtet, dass jemand zwischen Server und Client den Netzwerk-Verkehr abhört und vertrauliche Daten abfängt.
Zur Aktivierung der Verschlüsselung sollten sowohl Client als auch Server die TCP/IP Network Library für die Kommunikation verwenden. Dazu führt man das entsprechende Netzwerk-Utility aus (Start > Programme > Microsoft SQL Server > Server Network Utility auf dem Server und Start > Programme > Microsoft SQL Server > Client Network Utility auf dem Client) und aktiviert das Kontrollkästchen "Force Protocol Encryption". Alle Verbindungen zwischen Client und Server werden von nun an verschlüsselt.
Die Verschlüsselung hat natürlich ihren Preis. Beim Aufbau einer Verbindung ist einiges an Mehraufwand nötig und sowohl Client als auch Server müssen den Code zur Verschlüsselung und Entschlüsselung der Datenpakete ausführen. Es ist also erhöhter Rechenaufwand erforderlich, was u. U. auch zu messbaren Geschwindigkeitseinbußen bei aktivierter Verschlüsselung führen kann. Doch wenn man die vollständige Kontrolle über die Netzwerkpakete (also die tatsächlich über die Leitung zwischen Client und Server ausgetauschten Daten) verloren hat, ist eine Verschlüsselung wahrscheinlich empfehlenswert.
Verschlüsselung mit Lücken
Es wird vielleicht aufgefallen sein, dass in der Liste der verschlüsselbaren Dinge offensichtlich etwas fehlt: die Daten in den Tabellen. SQL Server bietet von Haus aus keine Unterstützung für die Verschlüsselung solcher Daten vor der Speicherung. Falls man die in SQL Server gespeicherten Daten schützen will, gibt es zwei Möglichkeiten: Einmal kann man mithilfe der Schlüsselwörter GRANT und DENY festlegen, wer Zugriff auf die Daten innerhalb von SQL Server hat, wie in einem früheren Artikel dieser Reihe bereits beschrieben. Wenn Anwender eine Tabelle gar nicht erst öffnen können, spielt es auch keine Rolle, ob die darin enthaltenen Daten verschlüsselt sind oder nicht.
Zweitens: Falls man die Daten tatsächlich verschlüsseln will, sollte man sich keine eigene Verschlüsselungslösung basteln. Es gibt eine Reihe kommerzieller Produkte mit bewährten Verschlüsselungsalgorithmen auf dem Markt, auf die man zurückgreifen kann. Eine gute Übersicht findet sich in den SQLSecurity FAQ. SQL Injection ist der Name für eine allgemeine Klasse von Attacken, die es böswilligen Anwendern ermöglichen, auf Daten zuzugreifen, Server-Einstellungen zu verändern oder sogar den ganzen Server zu kapern, wenn man nicht vorsichtig ist. SQL Injection ist kein spezielles Problem von SQL Server, sondern betrifft alle unsauber geschriebenen Anwendungen. Da man sicherlich im Laufe seines Lebens auf eine solche Anwendung stoßen wird, sollte man das Problem verstanden haben und wissen wie man es behebt.
Lokalisierung von Schwachstellen
Einfallstore für SQL Injection entstehen, wenn gutgläubige Anwendungsentwickler eine WHERE-Klausel erstellen, bei der Benutzereingaben verwendet werden. Eine schlichte ASP-Anwendung könnte z. B. erlauben, dass der Benutzer eine Kunden-ID eingibt und der Ansprechpartner der zugehörigen Firma ausgegeben wird. Falls die Kunden-ID als Bestandteil des Requests von der ASP-Seite übergeben wird, könnte der Entwickler den folgenden Code schreiben, um die Daten abzurufen:
Wo liegt also das Problem? Wenn ein Benutzer eine Kunden-ID eingibt, erhält er den zugehörigen Ansprechpartner. Das geht doch in Ordnung, oder?
Abruf zusätzlicher Daten
Nun nicht ganz. Zum einen kann der Hacker den Namen eines Ansprechpartners erfahren, selbst wenn er gar keine Kunden-ID kennt. Er muss dabei nicht einmal eine erraten. Um dies zu erreichen, gibt er einfach den folgenden Text in das Eingabefeld ein, wo die Anwendung die Kunden-ID erwartet:
Wenn man dies in den Code einfügt, wird daraus die folgende Abfrage:
Durch Anwendung des UNION-Operators auf alle leeren und nicht-leeren Kunden-IDs gibt diese Abfrage alle Ansprechpartner aus der Datenbank aus! Die Response.Write-Anweisung würde direkt die ersten dieser Namen auf der Antwortseite ausgeben. Tatsächlich kann man mit dieser UNION-Methode beinahe alles aus einer Datenbank herausholen. Wenn man Folgendes als Kunden-ID eingibt:
wird daraus die folgende SQL-Anweisung:
Voilá, schon hat der Hacker den Namen des ersten Mitarbeiters aus der Datenbank.
Daraus wird die folgende SQL-Anweisung:
Das Semikolon trennt für SQL Server mehrere Anweisungen, also gibt es hier zwei Anweisungen. Die erste fragt einen nichtexistenten Ansprechpartner ab, die zweite löscht die gesamte Kundentabelle! Der doppelte Bindestrich (--) ist ein SQL Server-Kommentarzeichen, das verhindert, dass das abschließende Anführungszeichen einen Syntaxfehler verursacht.
Mit dieser Variante kann ein Angreifer jede beliebige SQL-Anweisung oder gespeicherte Prozedur auf dem Server ausführen. Mithilfe der erweiterten gespeicherten Prozedur xp_cmdshell kann ein Angreifer sogar Befehle auf Betriebssystemebene ausführen. Dies ist selbstverständlich ein ernstes Problem.
Selbstschutz
Wie schützt man sich also vor einer SQL Injection? Die erste Antwort lautet ganz schlicht: Man darf Benutzereingaben nie direkt in einer WHERE-Klausel verwenden. Stattdessen sollte man gespeicherte Prozeduren mit Parametern benutzen. Im Falle der obigen ASP-Seite würde der entsprechend geänderte Teil so aussehen wie in Listing A[1].
Selbst wenn man überzeugt ist, dass die eigenen Anwendungen keine solchen Sicherheitslücken aufweisen, sollte man sich immer an das Prinzip halten, nur die notwendigsten Berechtigungen zu vergeben. Das heißt, man sollte die übrigen in dieser Reihe vorgestellten Sicherheitsverfahren anwenden, so dass Anwender nur auf solche Daten zugreifen können, die sie auch benutzen. Auf diese Weise kann selbst eine eventuell übersehene Sicherheitslücke nicht zur Katastrophe führen.
URLs in diesem Artikel:
[1] = http:/