Erfahrungsbericht: CherryPy und Cheetah

Gute Links und Tutorials könnt ihr hier posten.
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 31. Mai 2007, 11:36

Leonidas hat geschrieben:Richtig, deswegen muss man auch den Referer prüfen, ob der POST auch von "deiner" seite kommt und nicht von wo anders.
Nein, ich glaube so einfach ist das bei "Cross-Site Request Forgery" nicht.

Wenn ich das richtig verstehe, dann wird ein gefälschter Request vom Kompromittierten Browser des Users abgesetzt. Somit ist die Session-ID und der Referrer gültig.

Auf der Wikipedia Seite sieht die Server-Seitige-Lösung so aus, das man bei jedem Request ein "Shared-Secret" mitschickt, der nur einmalig gültig ist. Siehe http://de.wikipedia.org/wiki/Cross-Site ... rverseitig

Aber das bietet IMHO kein Framework out-of-the-box... Die Frage ist auch, ob das wirklich eine Lösung ist. Man sollte wohl ehr einen Fokus auf Cross-Site Scripting setzten...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
tiax
User
Beiträge: 152
Registriert: Samstag 23. Juli 2005, 17:28
Kontaktdaten:

Donnerstag 31. Mai 2007, 11:38

Aber das bietet IMHO kein Framework out-of-the-box
Djang liefert dazu eine Middleware mit
Ne invoces expellere non possis
[url=xmpp://florian@florianheinle.de]xmpp:florian@florianheinle.de[/url]
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 31. Mai 2007, 11:46

Hallo!

Ich halte nicht sehr viel von der Trennung zwischen GET und POST. Beides kann sehr einfach simuliert werden. Und jemand der sich Gedanken darüber macht, wie er Webbenutzer überlisten kann, der ist sich auch bewusst, wie GET und POST arbeiten.

Im Gegenteil. Ich halte die Trennung zwischen GET und POST beim Programmieren einer Webanwendung für zusätzlichen Aufwand, den das Framework vom Programmierer fern halten sollte.

Wie auch immer. Man erhält von CherryPy die Auskunft, ob die Argumente per GET oder POST gekommen sind. -- Wenn man es braucht, oder glaubt es zu brauchen.

Code: Alles auswählen

cherrypy.request.method
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
thelittlebug
User
Beiträge: 188
Registriert: Donnerstag 20. Juli 2006, 20:46
Wohnort: Wien
Kontaktdaten:

Donnerstag 31. Mai 2007, 12:05

Ich hab das damals so gelöst:

Wichtige Änderungen (löschen des Accounts, Ändern des Passworts) nur unter zusätzlicher Eingabe des Passworts möglich.
Andere Bereiche waren so geschützt:
Bei einem Besuch einer Administrativen Seite wurde ein Schlüssel erstellt. Dieser Wert wurde für den Benutzer zusätzlich in einer Tabelle gespeichert.
Dieser Schlüssel wurde jeder möglichen Aktion(POST, GET) zusätzlich angehängt. Nur wenn beim Aufruf der Aktion der Schlüssel zur Session passte wurde die Aktion auch ausgeführt. Bissal umständlich, aber es hat geklappt.

lgherby

edit: Bei Browsergames ist es sehr beliebt in den Foren oder im IRC mal Nachrichten wie die hier loszulassen: Hier eine Möglichkeit zu cheaten, klicke einfach auf http://www.unsertollesbrowsergame.de/us ... ion=delete
Das schlimme dabei, es geht bei 95% der Browsergames :D
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 31. Mai 2007, 12:16

gerold hat geschrieben:Man erhält von CherryPy die Auskunft, ob die Argumente per GET oder POST gekommen sind.
Hallo!

Und so lässt sich CherryPy dazu bewegen, nur mehr per GET gekommene Aufrufe auszuliefern, wenn diese keinen "query_string" enthalten.

Code: Alles auswählen

def no_get_allowed():
    is_get = cherrypy.request.method.upper() == "GET"
    if is_get and cherrypy.request.query_string:
        raise cherrypy.HTTPError(message = "Only GET without query_string allowed!")

cherrypy.tools.no_get_allowed = cherrypy.Tool('on_start_resource', no_get_allowed)
In der INI-Datei muss man dieses Tools dann noch so aktivieren:

Code: Alles auswählen

[/]
tools.no_get_allowed.on = True
Ab jetzt gibt es einen Fehler, wenn Parameter über den URL übergeben werden.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 31. Mai 2007, 12:53

Hallo!

Zwei neue Kapitel sind dazu gekommen:

- Was wird von CherryPy bei welchem URL ausgeliefert?
- Bilder und andere statische Dateien

http://halvar.at/python/cherrypy_cheetah/

lg
Gerold
:-)

Edit: Links ausgebessert
Zuletzt geändert von gerold am Dienstag 4. Dezember 2007, 20:46, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Donnerstag 31. Mai 2007, 12:53

Leonidas hat geschrieben:Richtig, deswegen muss man auch den Referer prüfen, ob der POST auch von "deiner" seite kommt und nicht von wo anders. Aber wenn wir das Beispiel von fme nehmen, dann kann dem User kein POST aus einem Link im Profil untergeschoben werden. Und wenn daten per POST kommen, muss man eben Referer prüfen.
Hm das schlechte am Referer prüfen ist das es idiotische "Fi0rW4llz" und ähnliches gibt welche den Referer einfach löschen. Da Frage ich mich ernsthaft warum sie nicht überprüfen ob Referer != Host und ihn nur dann löschen. Wobei ich für mich persönlich denke das jeder der sowas Benutzt selber schuld ist und man ihn ruhig darauf aufmerksam machen soll. Kunden sind da oft anderer Meinung.
Gerold hat geschrieben: Ich halte nicht sehr viel von der Trennung zwischen GET und POST.
GET und POST sind zwei verschiedene Dinge, wieso sollte man sie gleich behandeln? Eine GET Anfrage sollte zum Beispiel keine Nebeneffekte haben.
thelittlebug hat geschrieben:Bei Browsergames ist es sehr beliebt in den Foren oder im IRC mal Nachrichten wie die hier loszulassen: Hier eine Möglichkeit zu cheaten, klicke einfach auf http://www.unsertollesbrowsergame.de/us ... ion=delete
Das schlimme dabei, es geht bei 95% der Browsergames
Die noch böseren Jungs hängen so etwas wie

Code: Alles auswählen

[img]http://example.com/account.php?action=delete[/img]
in ihre Foren Signatur oder Interne Messages ;)

Zu Seiten die so verwundbar waren Zählen (laut Wikipedia) unter anderem Amazon, Google AdWords, und natürlich Digg (Die sich selbst Diggende Story ;) )
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 31. Mai 2007, 13:01

veers hat geschrieben:GET und POST sind zwei verschiedene Dinge, wieso sollte man sie gleich behandeln? Eine GET Anfrage sollte zum Beispiel keine Nebeneffekte haben.
Hallo veers!

GET und POST sind nur zwei Methoden, innerhalb des HTTP-Protokolls, mit denen Daten über das HTTP-Protokoll zum Server übertragen werden. Das Ergebnis sind Daten, die dem Server bekannt gegeben wurden. Warum soll ich mich als einfacher Webprogrammierer darum kümmern müssen, und unterscheiden, ob die Daten per GET oder per POST an mich gesendet wurden? Mir ist es ja auch egal, ob ich eine Datei per HTTP oder per FTP herunter lade. Wichtig ist im Endeffekt nur, dass ich die Datei danach zur Verfügung habe.

Also ganz habe ich es noch nicht verstanden, warum ich zwischen GET und POST unterscheiden sollte.

Ob ich jetzt als böser Junge den URL

Code: Alles auswählen

http://example.com/account.php?action=delete
verbreite, oder einen URL, der auf eine Seite zeigt, die automatisch per JavaScript ein "Submit" eines Formulars auslöst, macht doch fast keinen Unterschied mehr, oder doch? Da finde ich GET sogar noch besser, da man hier schon am URL erkennt, dass etwas passiert, was ich evt. nicht will.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 31. Mai 2007, 13:11

gerold hat geschrieben:Also ganz habe ich es noch nicht verstanden, warum ich zwischen GET und POST unterscheiden sollte.
Ich bin der Meinung man muß bei einem Client-Request nicht zwischen GET und POST auf dem Server unterscheiden. Da sehe ich eigentlich keine Notwendigkeit.

Allerdings sollte man bei Navigation/Formulare gezielt POST oder GET benutzten. Aktionen, die irgendwelche Daten verändern, sollten IMHO niemals mit GET dem Client angeboten werden. Wobei das manchmal viel einfacher zu Programmieren ist, weil man kein HTML-Formular bauen muß, sondern einfach nur ein Link anbieten muß.

Der User sollte aber IMHO jede URL gefahrlos als Bookmark speichern können.

Mit djangos URL Mapper sind GET Geschichten eh in der Ursprünglichen Form ausgestorben. Dort wird die URL ...?view=123 z.B. zu .../view/123/ oder .../view/123.html
Das sieht auch hübscher aus ;)

Siehe auch http://www.w3.org/Provider/Style/URI

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 31. Mai 2007, 13:32

jens hat geschrieben:Allerdings sollte man bei Navigation/Formulare gezielt POST oder GET benutzten.
Hallo!

- Navigationslinks mit GET
- Formulare mit POST
- Serverseitig keine Unterscheidung

Das ist genau meine Meinung.

Falls jetzt jemand nicht weiß, was ich mit Navigationslinks meine:

Code: Alles auswählen

<a href="http://example.com/artikelliste.html?from_id=100&to_id=199">Next 100 Articles</a>
EDIT:
@veers:

Nach langem Nachdenken: :-) Das Verhindern von solchen URLs:

Code: Alles auswählen

http://example.com/account.php?action=delete
könnte den Vorteil bringen, dass diejenigen, die nichts von GET und POST wissen, nicht so viel Schaden anrichten können. Wobei ich glaube, dass man jegliche Änderung auf einer Website nur dann zulassen sollte, wenn der Benutzer authentifiziert ist.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Donnerstag 31. Mai 2007, 18:00

POST sollte man für alles verwenden, was Daten auf dem Server ändert - Ausnahmen können Logfile-Einträge, Sessions und Zugriffsstatistiken sein.

Nicht ohne Grund fragen Browser auch nach, ob man bei einem erneuten Laden einer Seite die Daten auch erneut absenden möchte.

Ein Schutz ist das dennoch nicht. Templates und Controller sollte man aber schon so gestalten, dass Erstgenanntes berücksichtigt wird. Über RESTful Dispatching oder (etwas unschöner) über einfache Abfrage von REQUEST_METHOD lässt sich das auch forcieren.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Donnerstag 31. Mai 2007, 18:11

gerold hat geschrieben: Genshi war ziemlich weit oben in meiner Rangliste. Ich konnte mich nur nicht in die Umgekehrte Reihenfolge der Code-Wiederverwendung eindenken. Mit TAL/METAL ruft man von jeder TAL-Seite aus das Makro der Hauptseite auf und füllt "Slots" mit den geänderten Daten. Bei Genshi scheint es genau umgekehrt zu funktionieren. Man arbeitet ständig mit der Hauptvorlage und ändert die Incluces je nach anzuzeigender Seite. Zumindest wurde es mir in den paar Stunden, die ich Genshi gewidmet hatte, so vermittelt.

Ich habe auf die Schnelle kein gutes Beispiel gefunden und da es sich, wie oben schon erwähnt, (für mich) ungewohnt anfühlte, habe ich es nicht mehr weiter bedacht. Dann kommt noch dazu, dass ich mindestens schon fünf Designern/Grafikern/Freunden TAL/METAL beibringen wollt und nicht ein einziger ist mir darauf eingestiegen. (mir wäre es mit Genshi wohl kaum besser ergangen) Nur ein Kollege von mir (ein Administrator) kommt damit klar. Er hilft mir jetzt öfter mal bei Zope-Websites. Als ich letztens einem meiner Kollegen Cheetah zeigte, war alles nach ein paar Minuten klar. Sogar ``#for`` und ``#if`` wurde sofort verstanden. Ich musste nichts erklären. Es erklärte sich (fast) alles von selbst. Das ist wahrscheinlich der Grund dafür gewesen, warum ich bei Cheetah geblieben bin.
Was Include-Mechanismen oder Macros angeht bin ich persönlich mit dem TAL/TALES/METAL-Gespann (genutzt über das SimpleTAL-Paket) ins Straucheln gekommen und konnte mich nicht einfach in die Möglichkeiten der Wiederverwendung hineindenken. Dass sowas anderen nicht einfach beizubringen ist, kann ich mir gut vorstellen.

Mit dem Genshi-inspirierenden Kid erging es mir nicht besser, im Gegenteil. Auch der Umstieg von Kid auf Genshi erforderte wieder etwas Grübelei - allerdings haben die Migration-Docs das start vereinfacht.

Letztlich ist der wohl gängigste Ansatz mit Genshi, so nehme ich an, der, dass man in den Templates der einzelnen Seiten die spezifischen Inhalte wie Titel oder Body als Funktionen über py:def festlegt. Am Ende wird dann das Layout-Template per XInclude eingebunden, in welchem diese Funktionen aufgerufen werden.
Das scheint nicht der einzige mögliche Weg zu sein und auch in meinen Augen auch irgendwie nicht der "rundeste". Nach mehreren Experimenten zu alternativen, noch geradliniegeren(?) Vorgehen bin ich aber dabei geblieben. Und spätestens wenn man eine einfache Vorlage für die einzelnen Seitentemplates geschaffen hat und diese nur kopiert, kommt man damit auch gar nicht mehr in Kontakt.

Umgekehrt kann man wiederverwendbare Elemente (ebenfalls über Funktionen oder aber py:match) in einem separaten Template definieren, das allerdings im Template einer spezifischen Seite *oben* auf dem selben Wege einbinden und dann die vordefinierten Funktionen dort aufrufen.


Bei Text-Template-Engines wie Cheetah eine ist stört mich nachwievor, dass man if-Konstrukte je nach Fall auch schon mal doppelt ausführen muss, je nachdem ob man für etwas umschließende Tags ein-/ausblenden möchte oder nicht. Und das bedeutet für mich klar erschwerte Wartbarkeit und Lesbarkeit. Da haben Attribut-basierte Template-Sprachen natürlich die Nase vorn, während sie woanders Grenzen haben. Aber gut, da brauchen wir nicht wieder die Diskussion lostreten.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Donnerstag 31. Mai 2007, 18:46

gerold hat geschrieben:Wobei ich glaube, dass man jegliche Änderung auf einer Website nur dann zulassen sollte, wenn der Benutzer authentifiziert ist.
Das ist ja gerade das Problem beim CSRF, du bist authentifiziert, und ich bin in der Lage von aussehn Befehle im Scope deiner Session auszuführen.

Und wieso man unterscheiden sollte:
Ein weiterer Grund sind Prefetcher, die Laden einfach mal alles herunter was per GET erreichbar ist um das Browser schneller zu machen. Fasterfox macht sowas z.bsp.
Schlussendlich, ich machs so weil es der Standard so vorsieht. Ob das einen Webentwickler nun Interessieren sollte oder nicht ist eine andere Frage. Ich persönlich denke ja. Viele andere Leute anscheinend nein. Die Frage erinnert mich etwas an die Diskussion zu Validem HTML und zur verwendung von CSS.
gerold hat geschrieben:Da finde ich GET sogar noch besser, da man hier schon am URL erkennt, dass etwas passiert, was ich evt. nicht will.
Redirect ;)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 31. Mai 2007, 18:52

veers hat geschrieben:
gerold hat geschrieben:Da finde ich GET sogar noch besser, da man hier schon am URL erkennt, dass etwas passiert, was ich evt. nicht will.
Redirect ;)
Erwischt! :twisted:
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Samstag 2. Juni 2007, 15:32

Zuletzt geändert von gerold am Dienstag 4. Dezember 2007, 20:47, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten