Inhalt
Sicherheitslücke in der Datenbank behoben
Um die Sicherheit in Dreamweaver 8.0.2 und CS3 zu erhöhen, wurde die Verwendung dynamischer SQL-Parameter in Standarddatenätzen entfernt. Der ursprüngliche Code hat Datenbanken für SQL-Injections angezeigt. Die Verwendung vorbereiteter Anweisungen für ASP_VBS- und ColdFusion-Servermodelle behebt die Sicherheitslücke. Es war notwendig, der Seite eine Funktion hinzuzufügen, wenn der erste Datensatz angewendet wird, und diese Funktion dann von allen Datensätzen auf der Seite für PHP_MySQL aufzurufen. Diese Technik ähnelt den vorbereiteten Anweisungen von ASP_VBS und ColdFusion.
Um die Sicherheitslücke zu schließen, haben wir Flexibilität gegen Sicherheit eingetauscht. Wir möchten Entwicklern, die bereits Erweiterungen, die dynamische SQL-Abfragen verarbeiten müssen, entwickeln oder dies planen sowie Endbenutzern, die ihre Datensätze anpassen möchten, um dynamische Parameter zu akzeptieren, die Möglichkeit geben, diese benutzerdefinierten Datensätze in Dreamweaver zu bearbeiten.
SQL-Injections und Präventionsmethoden
Eine SQL-Injection ist eine Technik, die eine Sicherheitslücke nutzt, die in der Datenbankschicht einer Anwendung auftritt. Die Sicherheitslücke liegt vor, wenn Benutzereingaben entweder falsch nach in SQL-Anweisungen eingebetteten Zeichenfolgenliteral-Escapezeichen gefiltert werden oder Benutzereingaben nicht stark typisiert und dadurch unerwartet ausgeführt werden. Es handelt sich in der Tat um eine allgemeinere Klasse von Sicherheitslücken, die auftreten können, wenn eine Programmier- oder Skriptsprache in eine andere eingebettet ist. Weitere Informationen finden Sie auf Wikipedia.
Beispiel für SQL-Standardabfrage:
SELECT * FROM company_com WHERE name_com = '$companyName'
Im obigen Beispiel wird die Variable $companyName aus einem Eingabeformularfeld gelesen, sodass der Benutzer die vollständige Kontrolle darüber hat, welcher Wert gesendet wird. Bestensfalls gibt der Benutzer „Adobe“ (ohne Anführungszeichen) ein, entsprechend dem Firmennamen. Dann sieht die angegebene SQL-Abfrage folgendermaßen aus:
SELECT * FROM company_com WHERE name_com = 'Adobe'
Es gibt jedoch Fälle, in denen Benutzer die Website beschädigen und vertrauliche Informationen stehlen und/oder die Datenbank zerstören möchten. In Anbetracht des obigen Beispiels kann eine SQL-Injection leicht erreicht werden, indem die folgende Zeichenfolge eingegeben wird: „blabla 'OR' 1 '=' 1“ (ohne die umgebenden Anführungszeichen) . Durch die Angabe dieser Zeichenfolge hat der Benutzer Zugriff auf alle Unternehmen anstelle eines einzelnen Unternehmens. Die tatsächliche SQL, die ausgeführt wird, lautet wie folgt:
SELECT * FROM company_com WHERE name_com = 'blabla' OR '1'='1'
Wenn der Benutzer die gesamte Tabelle company_com löschen möchte, kann er dies tun, indem er einfach die folgende Zeichenfolge eingibt „x '; DROP TABLE company_com;--“ (ohne die umgebenden Anführungszeichen) . Hier ist die vollständige SQL-Abfrage:
SELECT * FROM company_com WHERE name_com = 'x'; DROP TABLE company_com; --'
Verwenden Sie eine der folgenden Maßnahmen, um Ihre Website vor SQL-Injections zu schützen:
- Beschränken Sie die Eingabe auf einen Mindestsatz zulässiger Zeichen, indem Sie automatisch alle anderen Zeichen entfernen, die außerhalb des angegebenen Bereichs liegen.
- Entfernen Sie alle Zeichen, die bei der Verwendung innerhalb einer SQL-Abfrage Probleme verursachen können (z.B. einfache Anführungszeichen).
- Verwenden Sie vorbereitete Anweisungen.
- Verwenden Sie Datenbankzugriffsrechte.
- Verwenden Sie gespeicherte Prozeduren.
Wir empfehlen vorbereitete Anweisungen, die ausführlicher beschrieben sind in Verwendung vorbereiteter Anweisungen. Dreamweaver 8.0.2 und CS3 verwenden den Ansatz für vorbereitete Anweisungen für ASP_VBS-, ASP_JavaScript-, Cold Fusion- und JSP-Servermodelle und den Escape-Ansatz des Benutzers für das PHP_MySQL-Servermodell. Weitere Informationen zu SQL-Injection-Angriffen finden Sie unter SQL Injection Attacks by Example (Beispiele für SQL-Injections).
Vorbereitete Anweisungen verwenden
Dreamweaver 8.0.2 und CS verwenden vorbereitete Anweisungen, da diese Lösung garantiert, dass das Ersetzen der tatsächlichen SQL-Parameter durch bestimmte Werte (möglicherweise per URL gesendet) auf dem Server und nicht auf der Seite erfolgt. Vorbereitete Anweisungen garantieren auch, dass der an SQL selbst übergebene Wert den geeigneten Datentyp hat und das geeignete Escaping verwendet (wenn ein Parameter vom Typ „int“ ist, kann der Benutzer keinen Buchstaben übermitteln, oder wenn ein Parameter vom Typ „text“ ist, wird die gesamte übergebene Zeichenfolge ordnungsgemäß entfernt, und der Benutzer hat nicht die Möglichkeit, eine SQL-Injection durchzuführen.)
Vorbereitete Anweisungen für die ASP_VBS- und ASP_JS-Servermodelle
Für ASP_VBS und ASP_JS verlassen wir uns auf die ADODB-Datenbankschicht. Das folgende Beispiel zeigt einen einfachen ASP_VBS-Datensatz, der einen dynamischen SQL-Parameter zum Filtern der Ergebnisse verwendet:
... <% Dim Recordset1__MMColParam Recordset1__MMColParam = "1" If (Request.QueryString("id_com") <> "") Then Recordset1__MMColParam = Request.QueryString("id_com") End If %> <% Dim Recordset1 Dim Recordset1_cmd Dim Recordset1_numRows Set Recordset1_cmd = Server.CreateObject ("ADODB.Command") Recordset1_cmd.ActiveConnection = MM_connContacts_STRING Recordset1_cmd.CommandText = "SELECT * FROM company_com WHERE id_com = ?" Recordset1_cmd.Prepared = true Recordset1_cmd.Parameters.Append Recordset1_cmd.CreateParameter("param1", 5, 1, -1, Recordset1__MMColParam) ' adDouble Set Recordset1 = Recordset1_cmd.Execute Recordset1_numRows = 0 %> ...Vorbereitete Anweisungen für das ColdFusion-Servermodell
ColdFusion bietet integrierte Unterstützung für vorbereitete Anweisungen. Das folgende Beispiel zeigt einen einfachen ColdFusion-Datensatz, der einen dynamischen SQL-Parameter zum Filtern der Ergebnisse verwendet:
... <cfparam name="URL.id_com" default="1"> <cfquery name="Recordset1" datasource="company_employee"> SELECT * FROM company_com WHERE id_com = <cfqueryparam value="#URL.id_com#" cfsqltype="cf_sql_numeric"> </cfquery> ...Simulierte vorbereitete Anweisungen für das PHP_MySQL-Servermodell
Vorbereitete Anweisungen für PHP sind ab MySQL 4.1 verfügbar. Da wir jedoch auch frühere Versionen von MySQL unterstützen wollten, haben wir beschlossen, eine benutzerdefinierte Funktion zu implementieren, die praktisch dasselbe tut. Das folgende Beispiel zeigt einen einfachen PHP-Datensatz, der einen dynamischen SQL-Parameter zum Filtern der Ergebnisse verwendet:
... <?php if (!function_exists("GetSQLValueString")) { function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "") { $theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue; $theValue = function_exists(„mysql_real_escape_string“) ? mysql_real_escape_string($theValue): mysql_escape_string($theValue); switch ($theType) { case "text": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "long": case "int": $theValue = ($theValue != "") ? intval($theValue) : "NULL"; break; case "double": $theValue = ($theValue != "") ? "'" . doubleval($theValue) . "'" : "NULL"; break; case "date": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "defined": $theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue; break; } return $theValue; } } $colname_Recordset1 = "-1"; if (isset($_GET['id_com'])) { $colname_Recordset1 = $_GET['id_com']; } mysql_select_db($database_connContacts, $connContacts); $query_Recordset1 = sprintf("SELECT * FROM company_com WHERE id_com = %s", GetSQLValueString($colname_Recordset1, "int")); $Recordset1 = mysql_query($query_Recordset1, $connContacts) or die(mysql_error()); $row_Recordset1 = mysql_fetch_assoc($Recordset1); $totalRows_Recordset1 = mysql_num_rows($Recordset1); ?> ...Dynamische Parameter in Standarddatenätzen berücksichtigen
Wie können wir uns also vor SQL-Injections schützen und gleichzeitig dynamische Parameter berücksichtigen und den resultierenden Code über das Bedienfeld „Serververhalten“ in Dreamweaver bearbeitbar halten? Die Lösung besteht darin, die dynamischen Parameter in die SQL-Abfrage selbst einzufügen, anstatt sie als klassische SQL-Parameter zu verarbeiten (die entweder über vorbereitete Anweisungen maskiert oder an SQL angehängt würden).
Wichtig: Benutzer können solchen Code nicht mithilfe der mit Dreamweaver 8.0.2 oder CS3 gelieferten Objekte und Serververhalten generieren (Beispiel: Einfügen eines Datensatzes über das Bedienfeld „Serververhalten“ oder die Einfügeleiste). Bei dieser Lösung muss der Benutzer den Code manuell bearbeiten oder eine Drittanbietererweiterung installieren, die diesen Code erstellt. Die Verantwortung für das Schreiben von sicherem Code liegt beim Benutzer oder Softwareentwickler eines Drittanbieters.
Mit dieser Methode können erfahrene Entwickler dynamische SQL-Abfragen erstellen. Der Missbrauch dieser Lösung gibt einem Hacker die Möglichkeit, unerwünschte Berechtigungen zu erhalten und/oder die Webseiten und die Datenbank zu beschädigen. Weitere Informationen zum Minimieren des Risikos einer SQL-Injection finden Sie unter SQL-Injections und Präventionsmethoden.
Die Hauptfälle, in denen diese Lösung angewendet werden sollte, sind folgende:
- Manuelles Erstellen/Aktualisieren einer SQL-Abfrage, um dynamische Parameter zu akzeptieren.
- Erstellen/Aktualisieren vorhandener Erweiterungen, um dynamische Parameter zu generieren.
Beide Anwendungsfälle werden in den folgenden Abschnitten beschrieben.
Manuelles Erstellen/Aktualisieren einer SQL-Abfrage, um dynamische Parameter zu akzeptieren, während der Datensatz in Dreamweaver weiterhin bearbeitet werden kann
Im folgenden Beispiel möchte der Benutzer einer dynamischen Tabelle Sortierfunktionen hinzufügen. Er beschließt, die Seite neu zu laden, während die Dateien und die Sortierrichtung (aufsteigend oder absteigend) in der URL übergeben werden. Ein erstes URL-Beispiel lautet:
http://www.mydomain.com/index.php?sortCol=name_com&sortDir=ascEine manuelle Kodierung ist erforderlich, um diese Aufgabe in Dreamweaver mithilfe des Serververhaltens auszuführen. Die folgenden Codebeispiele zeigen die Änderungen, die für jedes Servermodell vorgenommen werden müssen.
Wichtig: Bitte beachten Sie, dass keines der folgenden Beispiele eine Validierung für SQL-Injections aufweist. Sie dienen nur als Beispiele und sollte nicht in der Produktion eingesetzt werden. Der Einfachkeit halber sind die Beispiele nicht absolut sicher. Sie müssen sich vor SQL-Injections schützen. Weitere Informationen finden Sie unter SQL-Injections und Präventionsmethoden.
ASP_VBS
Vorher:
... <% Dim Recordset1 Dim Recordset1_cmd Dim Recordset1_numRows Set Recordset1_cmd = Server.CreateObject ("ADODB.Command") Recordset1_cmd.ActiveConnection = MM_connContacts_STRING Recordset1_cmd.CommandText = "SELECT * FROM company_com" Recordset1_cmd.Prepared = true Set Recordset1 = Recordset1_cmd.Execute Recordset1_numRows = 0 %> ...Nachher:
... <% Dim orderBy: orderBy = "" If (Request.QueryString("sortCol") <> "") Then orderBy = "ORDER BY " & Request.QueryString("id_com") If (Request.QueryString("sortDir") <> "") Then orderBy = orderBy & " " & Request.QueryString("sortDir") End If End If %> <% Dim Recordset1 Dim Recordset1_cmd Dim Recordset1_numRows Set Recordset1_cmd = Server.CreateObject ("ADODB.Command") Recordset1_cmd.ActiveConnection = MM_connContacts_STRING Recordset1_cmd.CommandText = "SELECT * FROM company_com " & orderBy & "" Recordset1_cmd.Prepared = true Set Recordset1 = Recordset1_cmd.Execute Recordset1_numRows = 0 %> ...ColdFusion
Vorher:
... <cfquery name="Recordset1" datasource="company_employee"> SELECT * FROM company_com </cfquery> ...Nachher:
... <cfparam name="URL.sortCol" default=""> <cfparam name="URL.sortDir" default="ASC"> <cfset orderBy=""> <cfif (#URL.sortCol# NEQ "")> <cfset orderBy="ORDER BY #URL.sortCol# #URL.sortDir#"> </cfif> <cfquery name="Recordset1" datasource="company_employee"> SELECT * FROM company_com #orderBy# </cfquery> ...PHP_MySQL
Vorher:
... <?php mysql_select_db($database_connContacts, $connContacts); $query_Recordset1 = "SELECT * FROM company_com"; $Recordset1 = mysql_query($query_Recordset1, $connContacts) or die(mysql_error()); $row_Recordset1 = mysql_fetch_assoc($Recordset1); $totalRows_Recordset1 = mysql_num_rows($Recordset1); ?> ...Nachher:
... <?php $orderBy = ""; if (isset($_GET['sortCol'])) { $orderBy = "ORDER BY " . $_GET['sortCol']; if (isset($_GET['sortDir'])) { $orderBy .= " " . $_GET['sortDir']; } } ?> <?php mysql_select_db($database_connContacts, $connContacts); $query_Recordset1 = "SELECT * FROM company_com " . $orderBy . ""; $Recordset1 = mysql_query($query_Recordset1, $connContacts) or die(mysql_error()); $row_Recordset1 = mysql_fetch_assoc($Recordset1); $totalRows_Recordset1 = mysql_num_rows($Recordset1); ?> ...Erstellen/Aktualisieren vorhandener Erweiterungen, um dynamische Parameter zu generieren, während der Datensatz in Dreamweaver weiterhin bearbeitet werden kann
Stellen Sie sich nun dasselbe Szenario wie oben vor, außer dass der Benutzer eine Erweiterung erstellen möchte, die den entsprechenden Code generiert, anstatt sich auf eine Kombination aus integrierter Funktionalität und manueller Bearbeitung zu verlassen. Die neue Erweiterung sollte den richtigen Code für die Servermodelle ASP_VBS, ColdFusion und PHP_MySQL generieren.
Wichtig: In den folgenden Abschnitten konzentrieren wir uns nur auf das Generieren von Code, der die Werte aus den URL-Parametern zum Erstellen einer dynamischen SQL-Abfrage verwendet. Der Hauptschwerpunkt besteht darin, den Code so zu generieren, dass er weiterhin von Dreamweaver erkannt wird und in Standard-Dreamweaver-Schnittstellen bearbeitbar ist. Dieses Tutorial behandelt weder die Validierung von Eingabedaten (über URL-Parameter) noch schützt es das endgültige SQL vor einem Versuch von SQL-Injections, da die Komplexität dieses Codes den Umfang sprengen würde. Der Entwickler ist allein dafür verantwortlich, das endgültige SQL vor SQL-Injections zu schützen.
Wir zeigen eine Demo-Erweiterung, die eine Verbindung und eine Tabelle als Eingabe verwendet und eine dynamische Tabelle generiert, in der alle Datensätze angezeigt werden. Außerdem wird das generierte SQL so aktualisiert, dass es die Variable „orderBy“ enthält, wie in den obigen Beispielen gezeigt. Die Erweiterung wurde für Dreamweaver 8.0.2 und CS3 entwickelt. Der generierte Code ist nicht absolut sicher, da das Ziel darin besteht, Datensätze mit dynamischen Parametern zu erstellen, die über Standard-Dreamweaver-Schnittstellen bearbeitbar bleiben. Der Quellcode der Erweiterung befindet sich im Ordner Konfigurationsordner des Benutzers.
In allen folgenden Codebeispielen wurden die hervorgehobenen Abschnitte hinzugefügt, um die Sortierfunktion über die URL-Parameter sortCol und sortDir zu aktivieren.
ASP_VBS
Der Code, der die entsprechende SQL-Abfrage für das ASP_VBS-Servermodell generiert, befindet sich in der Datei „[USER_CONFIGURATION_FOLDER]/Commands/My Dynamic Table.js“ im Ordner Konfigurationsordner des Benutzers. Die erwähnenswerte Änderung ist in Zeile 130:
... 130: paramObj.encodedSQL = "SELECT * FROM " + paramObj.table + " \" & orderBy & \""; ...Die Teilnehmerdatei für das Serververhalten von MyDynamicTable ASP_VBS enthält einen zusätzlichen Teilnehmer, der der Seite die Variablendefinition „orderBy“ hinzufügt:
<group name="MyDynamicTable" version="9.0"> <groupParticipants> <groupParticipant name="connectionref_statement" /> <groupParticipant name="MyDynamicTable_orderBy" /> <groupParticipant name="recordset_main" /> <groupParticipant name="repeatedRegion_init2" /> <groupParticipant name="DynamicTable_main" /> <groupParticipant name="recordset_close" /> </groupParticipants> </group>ColdFusion
Die gleiche „[USER_CONFIGURATION_FOLDER]/Commands/My Dynamic Table.js“ im Konfigurationsordner des Benutzers enthält auch den Code für das ColdFusion-Servermodell; die relevante Änderung in diesem Fall ist in Zeile 138:
... 138: paramObj.SQLStatement = "SELECT * FROM " + paramObj.table + " #orderBy#"; ...Die Teilnehmerdatei für das ColdFusion-Serververhalten „MyDynamicTable“ enthält einen zusätzlichen Teilnehmer, der der Seite die Variablendefinition „orderBy“ hinzufügt:
<group name="MyDynamicTable" version="9.0"> <groupParticipants> <groupParticipant name="MyDynamicTable_orderBy" /> <groupParticipant name="Recordset_main" /> <groupParticipant name="DynamicTable_main" /> <groupParticipant name="RepeatedRegion_pageNum" /> <groupParticipant name="RepeatedRegion_maxRows" /> <groupParticipant name="RepeatedRegion_startRow" /> <groupParticipant name="RepeatedRegion_endRow" /> <groupParticipant name="RepeatedRegion_totalPages" /> </groupParticipants> </group>PHP_MySQL
Das letzte Servermodell in der Erweiterung ist PHP_MySQL. Die relevante Änderung in der Datei „[USER_CONFIGURATION_FOLDER]/Commands/My Dynamic Table.js“ im Konfigurationsordner des Benutzers ist in Zeile 122:
... 122: paramObj.SQLStatement = "SELECT * FROM " + paramObj.table+ " \" . $orderBy . \""; ...Die Teilnehmerdatei für das Serververhalten von MyDynamicTable PHP_MySQL enthält einen zusätzlichen Teilnehmer, der der Seite die Variablendefinition „orderBy“ hinzufügt:
<group name="MyDynamicTable" version="9.0"> <groupParticipants> <groupParticipant name="Connection_include" /> <groupParticipant name="MyDynamicTable_orderBy" /> <groupParticipant name="EditOps_SQLValueString" /> <groupParticipant name="Recordset_main" /> <groupParticipant name="DynamicTable_main" /> <groupParticipant name="Recordset_close" /> </groupParticipants> </group>Pro
Das oben beschriebene Verfahren hat mehrere Vorteile, unter anderem folgende:
- Die erfahreneren Entwickler können die SQL-Injection-Schwachstelle nutzen, um komplexere SQLs dynamisch zu erstellen.
- Die erstellten Datenätze können weiterhin in Dreamweaver bearbeitet werden.
- Es ist nicht schwierig, in vorhandene Dreamweaver-Erweiterungen zu integrieren, die Datensätze mit dynamischen SQL-Parametern generieren.
- Der von Dreamweaver generierte Standardcode bleibt unverändert. Entwickler, die keine dynamischen Abfragen benötigen (und ihre Clients), können sicher sein, dass der von Dreamweaver geschriebene Code sicher ist.
Kontra
Da Dreamweaver nicht standardmäßig für die Unterstützung dieser Methode entwickelt wurde, weist es auch einige Nachteile auf, darunter:
- Der mit der in diesem Dokument beschriebenen Methode generierte Code ist anfällig für SQL-Injections und muss daher auf andere Weise geschützt werden. Zu diesen Schutzmethoden gehört u. a.:
- Sicherstellen, dass der Endbenutzer die SQL-Injection-Methode nicht zum Erstellen der Webseite und/oder Datenbank verwenden kann.
- Escapezeichen für die Argumente setzen, bevor sie das eigentliche SQL erreichen.
- Sicherstellen, dass der Benutzer, selbst wenn er es schafft, Ihren Code zu beschädigen, keine vertraulichen Informationen stiehlt und/oder die Datenbank nicht umfasst.
- Zwei bekannte Probleme, die erst behoben werden können, wenn die nächste Version von Dreamweaver veröffentlicht wird:
- ColdFusion: Einfache Datensatz-UI entfernt die Hash-Werte um Variablennamen aus der SQL-Abfrage, wenn diese bearbeitet und dann wieder angewendet werden.
- ColdFusion, ASP_VBS, ASP_JS: Die Testschaltfläche in der erweiterten Datensatz-Benutzeroberfläche funktioniert nicht, wenn die SQL-Abfrage Variablennamen enthält
Speicherort des Konfigurationsordners des Benutzers
- Windows XP
C:\Dokumente und Einstellungen\[Benutzername]\Application Data\Adobe\Dreamweaver 9\Configuration
- Windows Vista
C:\Benutzer\[Benutzername]\AppData\Roaming\Adobe\Dreamweaver 9\Configuration
- Mac OS 10.4.x
/Benutzer/[Benutzername]/Library/Application\ Support/Adobe/Dreamweaver\ 9/Configuration