Eines der grundlegendsten Probleme, welches alle serverseitigen Programmiersprachen
gemeinsam haben, ist die "ab Werk" eingebaute Anfälligkeit gegenüber
URL-Hacking.
Das klassische Beispiel ist wohl das folgende:
<cfquery name="getData" datasource="#request.dsn#"> select something from theTable where ID = #url.ID# </cfquery>
Was nun geschieht, wenn man die Seite mit page.cfm?id=5;drop%20database aufruft,
kann sich jeder ausmalen (Voraussetzung ist natürlich eine schlecht aufgesetzte
Datenbank)…
Man kann (und sollte!) hier natürlich zu CFQUERYPARAM und generellen
Plausibilitätsabfragen
mit CFIF greifen, allerdings ist dies meiner Meinung nach nur die halbe
Miete. Deutlich sicherer fährt
man, wenn die zu übergebenden URL-Variablen verschlüsselt und somit
weitmöglichst
gegen Manipulation geschützt werden. 100%ige Sicherheit gibt’s natürlich
nie, aber man sollte es den bösen Buben so schwer wie möglich machen.
🙂
Das Prinzip
Grundlage des Systems, welches ich mir ausgedacht habe, ist der Custom Tag
cf_cryp von Jackson Moore. Prinzipiell wollte ich erreichen, dass man
sowohl verschlüsselte, als auch normale URL-Variablen übergeben kann,
ohne sich darum kümmern zu müssen, ob nun eine Entschlüsselung nötig
ist oder nicht. Zudem wollte ich erreichen, dass man als Programmierer
keine großen Umstellungen einplanen muss, also ganz normal mit URL-Variablen
weiterarbeiten kann.
Coding
Die Ideale Stelle für eine automatische Entschlüsselung eines verschlüsselten
Querystrings ist natürlich die Application.cfm. Ich nutze hierzu folgenden
Code:
<!--- encryptkey setzen ---> <cfset request.encryptkey="Blog_in_Black"> <!--- wenn ein querystring oder form.values vorhanden ist, string entschlüsseln ---> <cfif (len(cgi.query_string) and not find('=', cgi.query_string)) or isdefined("form.values")> <cfscript> //je nach situation string und scope setzen if(len(cgi.query_string)) { decodeme=cgi.query_string; scope="url"; } else { decodeme=form.values; scope="form"; } </cfscript> <!--- string entschlüsseln ---> <cf_cryp type="de" string="#decodeme#" key="#request.encryptkey#"> <!--- aus dem entschlüsselten string wieder variablen bilden ---> <cfloop list="#cryp.value#" delimiters="&" index="idx"> <cfset name=left(idx,FindNoCase("=",idx)-1)> <cfset wert=right(idx,len(idx)-FindNoCase("=",idx))> <cfset "#scope#.#name#" = wert> <!--- für's debugging <cfoutput>#scope#.#name# = #wert#<br></cfoutput> ---> </cfloop> </cfif>
Wie man sieht, geht der Code noch einen Schritt weiter und entschlüsselt
bei Bedarf auch den Inhalt von form.values, also ist auch eine verschlüsselte
Übergabe von Formularwerten möglich.
Damit das System in dieser Form funktioniert, musste ich an cf_cryp eine
kleine Anpassung in Zeile ~89 vornehmen:
<cfif findnocase("J",string,1) is 0> <!--- <cfthrow type="cryp" message="nochecksum"> ---> <!---marcus raphelt <cfml@raphelt.de>: added cfexit to suppress exceptions in cfmx---> <cfexit method="EXITTAG"> <cfelse>
Der Kommentar sagt’s bereits: unter CFMX gibt cf_cryp eine Exception aus,
wenn der übergebene String nicht dekodierbar ist. Dies wird zwar mit
dem not find(‘=’, cgi.query_string)weitestgehend
abgefangen, aber ich will’s nicht darauf anlegen, denn es könnte auch
z.B. ein Aufruf wie page.cfm?myVar
stattfinden.
Was geschieht nun in der Application.cfm?
Ich gehe hier nur auf die URL-Variablen ein – beim Form-Scope ist es
das gleiche, nur dass eben ein anderer Wert für scope gesetzt
wird. Es wird nachgesehen, ob ein Query-String übergeben wurde,
und ob er kein Gleichheitszeichen enthält (das ist bei mit cf_cryp
kodierten Strings nicht möglich). Ist dies der Fall, so wird
der Query-String an cf_cryp zur Entschlüsselung übergeben.
Zurückgegeben wird dann der "echte" Querystring, z.B. itemID=300&viewmode=full&bgcolor=white,
welcher dann über eine Schleife in Variablen des gewünschten
Scopes, in diesem Fall URL, umgewandelt wird. Das bedeutet gleichzeitig,
dass man im Zieltemplate wieder URL-Variablen zur
Verfügung hat und quasi normal weiterprogrammieren kann.
Übergabe
Den zu übergebenen Wert muss man vorher zusammenbauen und verschlüsselt übergeben.
Hier ein kleines Beispiel:
<!--- zu übergebenden querystring zusammenstellen ---> <cfset theQueryString = "itemID=300&viewmode=full&bgcolor=white"> <!--- querystring verschlüsseln ---> <cfmodule template="cryp.cfm" type="en" string="#theQueryString#" key="#request.encryptKey#" > <cfoutput> <a href="index2.cfm?#theQueryString#">Normale Übergabe...</a><br> <a href="index2.cfm?#cryp.value#">Verschlüsselte Übergabe...</a></cfoutput>
Ergebnisseite
Auf der Ergebnisseite reicht ein Dump des URL-Scopes. Sorry an alle 4.x-User,
aber ich war zu faul, eine Loop zu nutzen. 😉
<cfdump var="#url#">
Erweiterbarkeit
Das System lässt sich natürlich in alle Richtungen erweitern. So könnte man
z.B. verschlüsselte Werte in Cookies schreiben oder Variablen, die im
Server-Scope liegen, vor unbefugten Blicken schützen (praktisch bei Virtuellen
Servern).
Nachteile
Ganz klar, durch die Ver-/Entschlüsselung hat man deutliche Performance-Einbußen.
Diese sind aber, wie ich finde, wegen der gewonnenen Sicherheit zu vernachlässigen.
Download
Natüüürlich – Abtippen wäre unnötiger Sport. Daher habe ich ein kleines ZIP-Archiv (5521 Bytes)
erstellt, in dem alle nötigen Dateien enthalten sind. Viel Spaß beim
Testen!
Feedback ist erwünscht! 🙂
agent m, 07.10.2003
Koennen auch cfid & cftoken verschluesselt uebergeben werden? Soviel mir bekannt ist,
koennen diese nicht manuell gesetzt werden …
Hi,
das habe ich noch nicht getestet. Dieses System habe ich mal für eine Applikation entworfen, die für cfid und cftoken Cookies genutzt hat.
bye,
marcus
Hi,
die Anfälligkeit der Url Parameter besteht ja eigentlich nur bei where etwas=#url.id# (ohne Hochkomma), oder?
Als schnelle Hilfe hab ich meine Abfragen mit where etwas=#val(url.id)# modifiziert.
Was meint Ihr?
Grüßchen
Carola
Hi Carola,
ja, val() ist hierbei eine schnelle Lösung. Sicherer ist cfqueryparam, noch schöner für den User z.B., wenn Du vorher auf isNumeric() prüfst und dann im Bedarfsfall eine Fehlermeldung ausgibst. Das ist allerdings gänzlich Geschmackssache 🙂
Das Verschlüsselungssystem ist eine gute Möglichkeit, es gar nicht erst zu URL-Manipulationen kommen zu lassen.
Comments on this entry are closed.