Sicherheitsfrage: Manipulation von Javascript im Browser

Saugkraft

Aktives Mitglied
Thread Starter
Dabei seit
20.02.2005
Beiträge
8.998
Reaktionspunkte
3.190
Hallöchen,

ich frage mich gerade, ob es möglich ist das Javascript einer Seite im Browser zu manipulieren, nachdem die Seite geladen wurde, bzw. Javascript Befehle abzusetzen.

Als Beispiel: Ich lade eine Seite, die beim Klick auf einen Button bestimmte Parameter per AJAK postet. Die Parameter sind "fest" verdrahtet, indem Sie dem Client im HTML Code geliefert werden. Also zum Beispiel:
Code:
<input type="button" onclick="funktion(10, 20)" />

Frage 1: Kann ich, nachdem die Seite geladen wurde, den HTML Quelltext am Client verändern und ausführen, so dass ich also beispielsweise
Code:
funktion(20, 10)
aufrufe?

Frage 2: Kann ich das aufgerufene Script in der Seite verändern?
Wenn also zum Beispiel im Script:
Code:
funktion(p1,p2) {alert(p1);}
steht, dass daraus
Code:
funktion(p1,p2) {alert(p2);}
wird?

Hintergrund ist, dass ich ein paar Scripte habe, die ich, falls solche Änderungen möglich sind, mal auf ihre "Manipulationsresistenz" überprüfen müsste.

Und wo wir gerade schon dabei sind..

Frage 3:
Wenn ich das Ergebnis per AJAX geliefert bekomme und per
Code:
getElementById.div1.innerHTML = ergebnis;
in ein div schreibe, wird mir dieser DIV-Inhalt dankenswerterweise nicht im Quelltext angezeigt.

Lässt sich das umgehen, d.h. kann ich mir den ersetzten Inhalt des divs irgendwie anzeigen lassen?

Und wenn ja.. Wie kann ich das Umgehen umgehen? :D
Ich will also vermeiden, dass der neue Inhalt irgendwie eingesehen werden kann.
 
alles was der Browser bekommt kann auch nachträglich geändert werden. Z.b. Seite im Dateisystem speichern und dann "manipulieren" und wieder absenden. Teilweise bieten verschiedene Developertools (z.b. Firebug für Firefox) auch die Manipulation des DOM-Baums an...

das zur zweiten Frage: alles was der Browser anzeigt muss er ja intern irgendwo ablegen. Sprich es ist der DOM-Baum. Auch hier gibt es verschiedene Tools die es erlauben den aktuellen "Zustand" der Seite - sprich DOM-Baum - anzuzeigen. Da gibt es Erweiterungen für den Firefox oder aber auch die Developetools im Safari...

markus
 
Zum Austauschen/Einschleusen von JavaScript ist z.B. greasemonkey recht populär.
 
Als Beispiel: Ich lade eine Seite, die beim Klick auf einen Button bestimmte Parameter per AJAK postet. Die Parameter sind "fest" verdrahtet, indem Sie dem Client im HTML Code geliefert werden. Also zum Beispiel:
Code:
<input type="button" onclick="funktion(10, 20)" />

Frage 1: Kann ich, nachdem die Seite geladen wurde, den HTML Quelltext am Client verändern und ausführen, so dass ich also beispielsweise
Code:
funktion(20, 10)
aufrufe?

Dazu sollte es eigentlich schon reichen die Funktion in die Adresszeile einzugeben:

Code:
javascript:funktion(20, 10)
 
Danke Leute, das dachte ich mir schon. Die Bestätigung hilft mir insofern schonmal weiter, dass ich das gesamte System nochmal durchdenken muss.

Gar nicht. Im Firefox reicht dazu z.B. den Kontextmenübefehl "Auswahl Quelltext anzeigen".
Da erscheint das vorher leere Div nach dem Befüllen per innerHTML leer. Das ist insoweit gut. Allerdings zeigen die Developertools den Inhalt an. Mit Firebug dürfte das also ebenfalls einsehbar sein.

Na gut, dann muss ich die zu übertragenden Daten (bisher werden sie in hidden Feldern gespeichert) entsprechend kodieren, damit sie nicht im Klartext einsehbar sind.

Hat da jemand von euch eine Idee parat? Die Aufgabenstellung ist folgende:
Eine Seite hat ein Textfeld, in das der Benutzer z.B. ein Kennwort eingeben muss. Das korrekte Kennwort soll aber gleichzeitig mit dem Absenden der Seite ebenfalls übertragen und von der abfragenden Seite verglichen werden.

Ich weiß.. das ist der völlig falsche Ansatz, einen derartigen Vergleich durchzuführen. Normalerweise erledigt man sowas datenbankgestützt, damit die Daten nicht am Client vorliegen.

Das Problem ist dabei, dass ich dann bei der Auswertung nochmal diverse SQL Abfragen durchführen muss, ich aber auf ein exaktes Timing angewiesen bin. Ein erneutes Absenden der Seite mit weiteren Daten darf nicht erfolgen, bevor die erste Auswertung abgeschlossen ist.

Das lässt sich alles realisieren, einfacher wäre es aber, wenn ich die Vergleichsdaten mit der Antwort gleich mitliefern könnte.
 
Wenn überhaupt dann dürfte so etwas nur mit einem Token gehen ( also a la Kerberos).
Sprich: schick ein public token mit, mit dem eingegebenen Kennwort wird ein neues Token errechnet und aus diesem privat Token und dem public Token muß sich dann eine Bestätigung ermitteln lassen.
 
Hi,

wenn du eine Seite hast, die nur Browser "reagiert" kann es dir egal sein, ob jemand was manipuliert oder nicht. Z.b. du hast einen Web-Taschenrechner bereitgestellt, wo alles im Browser berechnet wird. Da kann es dir egal sein, wenn jemand "-" statt "+" ausführt.

Anders sieht es aus, wenn mit einem Server kommuniziert wird.

Hier heisst die OBERSTE REGEL

Security by Server

Es gibt immer wieder gern Leute die Validierungen ect. im Client machen. Echt Spassvögel welche vermutlich auch Basejumping ohne Fallschirm machen.

Zu deiner Frage:

Sicherheitsfrage: Manipulation von Javascript im Browser

Dies ist nicht nur mit Javascript so. Jeder Code der lokal ausgeführt wird, kann manipuliert werden. Ist bei C++ nicht anders, nur schwerer.

Wenn du den Leuten es schwerer machen willst, dann kannst du deinen Code komprimieren. Sprich, es gibt Tools welche den gesamten JS Code komprimieren und dadurch das debuggen und analysieren schwer gemacht wird. Da heisst die Funktion dann nichtmehr FillformData(), sondern nur a() und der ganze Code ist in einer Zeile.

Deine Aufgabenstellung habe ich nicht ganz verstanden.

Hat da jemand von euch eine Idee parat? Die Aufgabenstellung ist folgende:
Eine Seite hat ein Textfeld, in das der Benutzer z.B. ein Kennwort eingeben muss. Das korrekte Kennwort soll aber gleichzeitig mit dem Absenden der Seite ebenfalls übertragen und von der abfragenden Seite verglichen werden.

Wie kann ich mir das vorstellen? Einer gibt ein Kennwort ein, z.b. "123456". Jetzt sendest du die "123456" und zusätzlich das richtige Kennwort "Geheim4711"? Jetzt checkt man nur "Geheim4711", was dann als legitimes Kennwort gilt.

Check ich nicht. Was soll das bringen?

Dann noch:
Das Problem ist dabei, dass ich dann bei der Auswertung nochmal diverse SQL Abfragen durchführen muss, ich aber auf ein exaktes Timing angewiesen bin.

Wieso exaktes Timing? Und das bei http? Geht doch von der Technik schonmal gar nicht. Sprich, wenn du was zum Server schickst, wird die Zeit die vom Client zum Server geht und die Zeit der Verarbeitung nie exakt gleich sein. Du hast ausserdem noch eine DB als bottleleg und ausserdem sicherlich kein Echtzeit Betriebssystem.

Ein erneutes Absenden der Seite mit weiteren Daten darf nicht erfolgen, bevor die erste Auswertung abgeschlossen ist.

Wieso darf es nicht erfolgen? Wieso machst du keinen synchron request, dann kann der User auch nicht wieder was absenden. Du kannst natürlich noch zusätzlich eine "Sperr"-Div auf dem obersten Layer legen. Dann gehen alle Interaktionen ins leere.
 
Anders sieht es aus, wenn mit einem Server kommuniziert wird.
So ist es. Und das ist der Fall.

Hier heisst die OBERSTE REGEL
Security by Server
Auch richtig. Aber wir reden hier nicht vom Pentagon oder irgendwelchen empfindlichen Daten.

Was die erforderliche Sicherheit angeht.. Sagen wir, ich will vermeiden, dass jemand innerhalb einer geschlossenen Benutzergruppe (von mir aus ein Skatverein) unter dem Namen seiner Vereinskollegen Beiträge im internen Forum postet. Ist nur ein Beispiel. Den genannten Fall würde ich mit Session Variablen lösen.

Es soll vermieden werden, dass einer zuviel Langeweile hat und irgendwas tut, das er nicht soll. Da sich die Skatkumpels aber alle kennen und nur 1-2 den notwendigen Geek-Faktor aufbringen, kann man den Kreis recht gut eingrenzen. Da zwangsläufig auch andere Unstimmigkeiten auftreten würden, könnte man den Verursacher recht schnell ermitteln.

Insofern muss es nicht Fort-Knox sein, ein leicht erhöhter Schwierigkeitsgrad wäre mir durchaus recht.

Deine Aufgabenstellung habe ich nicht ganz verstanden.
Ich schleife ein paar Angaben auf Clientseite mit. In hidden-Feldern. Die enthalten die korrekten Angaben. Leicht modifiziert, damit keiner auf die Idee kommt, einfach mal so rumzuprobieren, eine Art Minimalstverschlüsselung. Das vergleiche ich mit dem, was der Benutzer im Klartext absendet.

Hier ist eben die Frage: Wieviel Wissen und Spaß am Probieren bringt jemand mit und inwieweit lohnt es sich, darauf zu reagieren.

Wieso exaktes Timing? Und das bei http? Geht doch von der Technik schonmal gar nicht. Sprich, wenn du was zum Server schickst, wird die Zeit die vom Client zum Server geht und die Zeit der Verarbeitung nie exakt gleich sein. Du hast ausserdem noch eine DB als bottleleg und ausserdem sicherlich kein Echtzeit Betriebssystem.
Eben. Timing trifft es auch nicht. Ich will die Antwortzeiten einfach kurz halten. Für manche Aktionen steht nur ein kurzes Zeitfenster zur Verfügung und das will ich nicht auch noch unnötig dadurch verkürzen, dass ich das Ergebnis überprüfe.

Ich erstelle einen Satz aus Daten, die nur für diesen Client in dieser konkreten Situation gelten. Ähnlich wie ein Cookie, nur dass ich es nicht über Cookies löse, weil die Daten nur zur Laufzeit vorliegen sollen.

Diese Daten kann ich am Server vorhalten (DB) oder am Client. Mit der bestehenden Lösung schleppt der Client die Daten solange mit, solange die "Anwendung" beim Client läuft. Fenster zu, Daten weg.

Der Client sendet also Vergleichsdaten und Benutzereingabe per AJAX zum Server. Der vergleicht beide, schreibt einen Eintrag in die DB und teilt dem Client mit: 200 OK. Daraufhin werden am Client neue Daten angezeigt und das ganze geht von vorne los.

Wenn ich die Vergleichsdaten am Server vorhalte, habe ich ein sehr großes Aufkommen an nutzlosen Daten, weil die nur zu Statuszwecken dienen (Welche Kombination von Daten wurde dem Benutzer angezeigt und wie muss das korrekte Ergebnis lauten?).

Aus der DB wird nur beim ersten Aufruf ein Komplettsatz geholt und geschieben wird nur ein einzelner Datensatz mit dem Ergebnis (Passt oder passt nicht).

Und zum anderen muss ich die Daten am Server jedesmal neu zusammenstellen. Das ist wieder mindestens eine Abfrage mehr.

Grundsätzlich kann ich auch einfach die Verschlüsselung der Vergleichsdaten verbessern. Aber hier braucht der Server im Zweifelsfall genauso lange für die Entschlüsselung wie für eine DB Abfrage.

Allerdings scheint mir das im Moment die beste Lösung zu sein. Da müsste ich nur mal sehen, welche Variante am schnellsten ist.

Die Daten selbst sind relativ trivial. Die lassen sich am besten binär darstellen. Zum Beispiel in Wordlänge: 010011101101111. Da könnte ich ein bisschen Bitshifting betreiben und die Anzahl der Bits an irgendein Session-Kriterium koppeln. (So ähnlich ist das jetzt auch gelöst). Hier ist wiederum die Frage, ob ich in der Zeit nicht auch bequem eine DB-Abfrage machen kann.
 
Ich hab die ganze Aktion zwar immernoch nicht verstanden aber dein Hauptvorhaben liegt ja glaube ich darin korrekte Daten aus einer Datenbank per Hidden Field mitzuschleifen um sie auf der Ergebnisseite zum Vergleich mit den Benutzereingaben nicht erneut auslesen zu müssen. Ist das soweit richtig?

Wenn nicht ignorier den Rest dieses Posts!

Wenn doch würde ich einfach vorschlagen aus den Daten aus der Datenbank einen MD5 Schlüssel zu generieren, diesen mitzusenden und auf der Ergebnisseite mit den Benutzereingaben ebenso zu verfahren um 2 MD5 Summen zu erhalten die du vergleichen kannst.
Allerdings würde ich einfach neu auslesen.
 
Ich hab die ganze Aktion zwar immernoch nicht verstanden aber dein Hauptvorhaben liegt ja glaube ich darin korrekte Daten aus einer Datenbank per Hidden Field mitzuschleifen um sie auf der Ergebnisseite zum Vergleich mit den Benutzereingaben nicht erneut auslesen zu müssen. Ist das soweit richtig?
Genau. Wobei Hauptvorhaben nicht ganz korrekt ist. So ist es bisher gelöst. Da mir das zu unsicher ist, überlege ich, wie ich es besser löse.

Wenn doch würde ich einfach vorschlagen aus den Daten aus der Datenbank einen MD5 Schlüssel zu generieren, diesen mitzusenden und auf der Ergebnisseite mit den Benutzereingaben ebenso zu verfahren um 2 MD5 Summen zu erhalten die du vergleichen kannst.
Allerdings würde ich einfach neu auslesen.
Klingt gut, allerdings befürchte ich, dass die Generierung eines MD 5 Schlüssels mit ASP Classic genauso lange dauert wie ein erneutes Auslesen.

Da das die robustere Variante ist, werde ich mir das mal überlegen. Möglicherweise bietet es sich auch an, einen Teil der Daten am Client vorzuhalten und den anderen Teil abzufragen.

Das klingt auch sicher alles komplizierter als es ist. Im Grunde ist das Problem relativ trivial. Vielleicht graut es mir auch einfach nur davor, die ganze Auswertung auf den Server zu verlagern, weil ich den ganzen Mist mit x Variablen und Statusabfragen dann nochmal neu programmieren muss. :D

Dass die Manipulation am Client so trivial ist, reicht mir aber eigentlich schon, das nochmal komplett aufzurollen. Alles eine Frage der Motivation. :)
 
@Saugkraft: Ich glaube du hast das Prinzip von "Security by Server" nicht verstanden. Um Sachen Serverseitig zu machen, brauchst du kein Pentagon, Fort Knox oder sonst was.

Wie ich es schrieb kommt drauf an was du machen willst. Wenn du mit der Applikation Geld verdienst, dann musst du "Security by Server" anwenden. Aber auch wenn du einen kostenlosen Dienst anbietest und die User dir vertrauen, wie z.b. in social networks oder einen Dienst wo man einen Kalender hat, wo man seine Daten eingeben kann ect.

In deinem Fall, lese ich raus, das du ein Online Skat Spiel anbietest. Wenn du willst, das Spieler welche zusammen online spielen dies machen sollen, ohne das 1-2 das cheaten anfangen, dann musst du auch "Security by Server" anwenden. Wenn dir das egal ist, dann eben nicht. Und dazu musst du auch nicht das Pentagon odersonst was sein.

Vielleicht habe ich es auch falsch verstanden und es ist kein Onlinespiel sondern einfach eine Plattform das einem forum ähnelt. Wenn du auch hier willst, das keiner Beiträge in anderen Namen postet, dann musst du auch dafür sorgen. Und ich wüsste auch nicht, was da so schwer sein sollte.

Der Benutzer muss sich einloggen, du prüft gegen eine DB und wenn ok, dann bildest du einen Session. Was soll da kompliziert sein? Du hast da initial nur 1 Datenbank Abfrage beim einloggen.

Ich schleife ein paar Angaben auf Clientseite mit. In hidden-Feldern.

Ich dachte du benutzt Ajax. Was soll das mit den hidden-Feldern??? Du hast in meinem Augen wenig Erfahrung mit Webentwicklung und wenn du dich in diese Richtung weiterentwickeln willst, musst du was dafür tun.
 
Doch, das Prinzip hab ich verstanden. Immerhin mache ich das schon eine Weile. ;)

Das mit dem Skatspiel/Forum war ein Beispiel. War ein schlechtes Beispiel. Mein Fehler. Damit wollte ich deutlich machen, dass irgendwelche Hindernisse nicht in vollem Umfang notwendig sind, weil kein wirklicher Schaden entsteht. Ich kann den tatsächlichen Anwendungsfall nicht in aller Gänze im Internet schildern. Ist so eine Art Betriebsgeheimnis. ;)

Bei der Frage der Sicherheit geht es auch darum, wen ich schützen will. Unsere Benutzer- und andere sensible Daten sind natürlich abgesichert. Die, bzw. das Vertrauen der User würde ich auch nicht leichtfertig durch Javascriptexperimente irgendeiner Gefahr aussetzen. Die Session wird natürlich erzeugt. Dort werden auch die wesentlichen Daten gespeichert und Berechtigungen, etc. werden über die Session geprüft.

Bei dem konkreten Fall liegt der "Schaden" etwas anders. Stell dir vor, du spielst Memory gegen den Rechner und die Anordnung der passenden Paare steht im Quelltext. Natürlich kannst du besch..ßen und im Quelltext nachsehen. Dann schadest du dir aber letztlich nur selbst, weil das Spiel dann keinen Spaß mehr macht.

Einem Dritten entsteht also kein Schaden. Die ganze Angelegenheit verliert lediglich ihren Reiz.

Ich hoffe, dass das Beispiel jetzt besser ist. :)

Jetzt zur Frage, warum ich das nicht mit erneuten Abfragen am Server löse. Sagen wir, das Memory-Spiel besteht insgesamt aus 400 Karten. Daraus wird ein Set von 100 Karten zufällig zusammengestellt und in Arrays gespeichert. Die Verteilung und die richtigen Kombinationen stehen ebenfalls in Arrays. Zum Server wird (in hidden Feldern) die korrekte Kombination und die aufgedeckte Kombination übermittelt.

Wenn ich das Set am Server hinterlege, kann ich das zwar über Sessions oder DB-gestützt erledigen, ich muss aber bei jedem Aufdecken den ganzen Krempel neu berechnen. Mit der Zeit zum Aufdecken wird es ebenfalls schwierig, weil die Zeit vom Absenden bis zur Bearbeitung hinzu kommt. Die Zeitmessung wird also ungenau. Und schlussendlich erzeuge ich eine Menge Datenoverhead am Server, der unnötig ist und die DB unnötigerweise belastet. Der Server muss nicht bei jedem Klick komplett involviert werden. Bei vielen gleichzeitigen Nutzern wird die Anwendung dadurch nicht gerade performanter.

Ergo stelle ich das komplette Set einmalig zusammen, übermittle es zum Client und der erledigt den Rest. Beim Absenden zwischendurch werden im Hintergrund lediglich die Zwischenergebnisse übermittelt.

Kurzum.. Wirfst du einen Blick in den Quelltext, hast du dich um deinen Erfolg beim Spiel beschissen.

Wie ich schon schrieb.. Das Problem ist eher trivial. Mich packt es dabei aber an meinem Ehrgeiz und ich hätte es gerne eleganter gelöst. Ist also meine ganz persönliche Challenge. Gib Cheatern aus Prinzip keine Chance, auch wenn dadurch kein wirklicher Schaden entsteht. Und mit der Anwendung wird kein Geld verdient. Das ist eher ein Zusatzfeature.

Ich hoffe, ich konnte etwas Verwirrung beseitigen. Beispiele sind nicht gerade meine Stärke. :D
 
Ok, jetzt habe ich es mittlerweile auch verstanden.

Die Frage ist für mich, warum machst du dir überhaupt Gedanken? Wenn einer sich selbst beschei...t soll er doch. Da würde ich keine einzige Sekunde meines Lebens daran vergeuden.

Du kannst auch alles serverseitig lösen, auch ohne ständig in die DB gehen zu müssen, aber es lohnt sich nicht. Bei dem Memoryspiel musst du auch nichts immer "neu berechnen", denn das verteilen der Karten machst du ja nur einmal am Spielbeginn. Die Daten die da jedesmal übertragen werden, sind ein Witz. Also Performance technisch, sollte sowas ein einfacher Server + einfache DB aushalten, ausser der Entwickler ist der Flaschenhals :)

Aber wie gesagt, es lohnt sich in diesem Falle auch nicht Serverseitig dies zu lösen, und damit schon längst nicht auch Clientseitig. Wenn man es Serverseitig löst, kann jeder halbswegs betuchte Entwickler, einen einfachen Bot schreiben, der die Requests inteligent tätigt und hat das Spiel in sehr kurzer Zeit gewonnen. Kannst gar nichts dagegen unternehmen. Es muss aber nichtmal ein Entwickler sein, sondern kann auch die Oma von nebenan. Dazu muss auch niemand mit Firebug oder ähnlichen sich den Clientcode anschauen. Einfach mit einem Knopfdruck ein Screenshot machen, schon hat man sich dies schnell gemerkt ;)
Also verschwende da keinen weiteren Gedanken dran.
 
Zurück
Oben Unten