ubuntuusers.de

[Python / Bottle] Session-Struktur selber machen

Status: Gelöst | Ubuntu-Version: Ubuntu 10.10 (Maverick Meerkat)
Antworten |

Glocke

Avatar von Glocke

Anmeldungsdatum:
1. März 2009

Beiträge: 880

Wohnort: Thüringen

Hi,

ich bastel momentan mit python und bottle an einer kleinen Webanwendung. Dabei ist mir aufgefallen, dass Bottle keine Sessions zur Verfügung stellt. Sicherlich könnte ich ein anderes Framework nehmen oder diesen Middleware-Weg gehen der auf der Bottle-seite angeboten wird. Aber ich möchte ein eigenes ähnlich funktionierendes konstrukt entwerfen.

Hier meine Ideen - ich würde die Sache gerne im Bezug auf Laufzeit und Sicherheit bewertet haben:

* Klasse "Session" erstellen

* Konstruktor legt einen lokalen Pfad fest (z.B. /var/www/cache) in dem die Sessions gespeichert werden

* ebenfalls erstellt der Konstruktor eine zb 30-stellige, zufällige Kombination von Ziffern sowie Klein- und Großbuchstaben, dieser String dient als "Session-ID". im gewählten pfad wird eine datei mit namen der session-id angelegt. falls diese existiert wird eine neue id generiert. dies geht solange, bis eine freie id gefunden wurde (oder irgendwie zu viele Anläufe unternommen wurden)

* die eigentlichen daten der session werden in der file abgespeichert und bei bedarf daraus geladen.

* um die datei (falls der pfad wie in meinem beispiel vom webserver abgefragt werden könnte) kann ein zugriffsschutz mittels htaccess hinzugefügt werden. da dieser sich nur auf den zugriff über den webserver begrenzt, kann das python-skript lokal auf das verzeichnis zugreifen.

* wird die session beenden, wird die datei entfernt.

wie der zugriff auf die datei genau aussieht ist imho erstmal nebensächlich (xml, ini kp)

was haltet ihr davon?

lg

PS: warum geht die liste nicht? was mache ich falsch - syntax hilfe sagt halt mit *-chen aber naja....^^

xabbuh Team-Icon

Anmeldungsdatum:
25. Mai 2006

Beiträge: 6411

Glocke schrieb:

PS: warum geht die liste nicht? was mache ich falsch - syntax hilfe sagt halt mit *-chen aber naja....^^

Pack noch ein Leerzeichen davor, dann läuft's. ☺

Glocke

(Themenstarter)
Avatar von Glocke

Anmeldungsdatum:
1. März 2009

Beiträge: 880

Wohnort: Thüringen

Du darfst diesen Beitrag nicht bearbeiten!

  • aber danke

  • jetzt weiß ich wie das geht 😉

zurück zum thema 😀

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Ich würde vorschlagen, Du guckst Dir mal den Code in flask an, der sich um Session kümmert. Evtl. kannst Du den ohne große Anpassungen übernehmen.

Als letzte Alternative nimmst Du gleich flask 😉

DasIch

Avatar von DasIch

Anmeldungsdatum:
2. November 2005

Beiträge: 1130

Dateisystem basierte Sessions sind recht schwierig zu implementieren weil man die Operationen auf dem Dateisystem atomar ausführen muss damit keine race conditions auftreten. Ich würde dir empfehlen einfach Werkzeug zu nutzen.

Solltest du es trotzdem selbst machen wollen verabschiede dich sofort von XML o.ä. komplexem du willst Zeit die fürs parsing und erzeugen draufgeht möglichst minimieren. Werkzeug/Flask nutzt üblicherweise pickle, dass ist aber ein Sicherheitsrisiko wenn du Daten die direkt vom User kommen serialisierst, solltest du letzteres tun nutz einfach JSON.

Glocke

(Themenstarter)
Avatar von Glocke

Anmeldungsdatum:
1. März 2009

Beiträge: 880

Wohnort: Thüringen

um mir händisches parsing im code zu ersparen, wollte ich eh pickle verwenden. inwiefern ist das ein sicherheitsrisiko?

atomare dateisystem operationen heißen doch quasi, dass ich mit den python boardmitteln (open(), read(), write(), close()) arbeite, oder? race conditions vermeide ich ja quasi, indem ich eine datei zb für den zugriff sperre bis die verarbeitung dieser abgeschlossen wurde.... richtig? sperrt open() dies und gibt close() die sperre wieder frei.

flask codeteile verwenden wäre eine alternative... aber ich möchte die sache mit bottle machen und nicht das framework wechseln (auch wenn beide auf den ersten blick sehr ähnlich von der handhabung wirken).

lg

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

flask codeteile verwenden wäre eine alternative... aber ich möchte die sache mit bottle machen und nicht das framework wechseln (auch wenn beide auf den ersten blick sehr ähnlich von der handhabung wirken).

Musst Du ja auch nicht; flask holt sich den Code eh aus werkzeug. Also könntest Du das einfach einbinden:

https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/contrib/sessions.py

https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/contrib/securecookie.py

Kannst natürlich auch so den Code rauskopieren und nutzen; allerdings zieht das ja doch einiges mit sich, weswegen ich dann werkzeug einfach als Abhängigkeit in Kauf nehmen würde.

Hast Du mal bei bottle geguckt, ob es da eine Art "Plugin" für sessions gibt? Iirc wollte da mal jemand etwas entwickeln...

DasIch

Avatar von DasIch

Anmeldungsdatum:
2. November 2005

Beiträge: 1130

Glocke schrieb:

um mir händisches parsing im code zu ersparen, wollte ich eh pickle verwenden. inwiefern ist das ein sicherheitsrisiko?

Pickle führt Code aus.

atomare dateisystem operationen heißen doch quasi, dass ich mit den python boardmitteln (open(), read(), write(), close()) arbeite, oder? race conditions vermeide ich ja quasi, indem ich eine datei zb für den zugriff sperre bis die verarbeitung dieser abgeschlossen wurde.... richtig? sperrt open() dies und gibt close() die sperre wieder frei.

open() und .close() sind nicht atomar. Schau dir an wie Werkzeug das macht.

flask codeteile verwenden wäre eine alternative... aber ich möchte die sache mit bottle machen und nicht das framework wechseln (auch wenn beide auf den ersten blick sehr ähnlich von der handhabung wirken).

Der hierfür relevante Teil findet sich in Werkzeug, nicht in Flask.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

DasIch schrieb:

open() und .close() sind nicht atomar. Schau dir an wie Werkzeug das macht.

Ich habe mir mal die save()-Methode aus dem sessions-Modul angeguckt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
    def save(self, session):
        fn = self.get_session_filename(session.sid)
        fd, tmp = tempfile.mkstemp(suffix=_fs_transaction_suffix,
                                   dir=self.path)
        f = os.fdopen(fd, 'wb')
        try:
            dump(dict(session), f, HIGHEST_PROTOCOL)
        finally:
            f.close()
        try:
            rename(tmp, fn)
            os.chmod(fn, self.mode)
        except (IOError, OSError):
            pass

Sehe ich das richtig, dass die Race Conditions durch Nutzung von mkstemp() und der Implementierung von rename() ausgeschlossen werden¹?

¹die augenscheinlich für Windows-Systeme aufwendig erscheint.

Gibt es einen Grund dafür, dass open() nicht atomar ist?

Glocke

(Themenstarter)
Avatar von Glocke

Anmeldungsdatum:
1. März 2009

Beiträge: 880

Wohnort: Thüringen

DasIch schrieb:

Glocke schrieb:

um mir händisches parsing im code zu ersparen, wollte ich eh pickle verwenden. inwiefern ist das ein sicherheitsrisiko?

Pickle führt Code aus.

kannst du das mal bitte genauer ausführen? ich kann dir nicht ganz folgen.

denkbar wäre auch das speichern der daten mittels mysql. wie sinnvoll ist das? optional in den datensatz ein "in bearbeitung"-flag rein, damit alle anderen prozesse die auf den datensatz zugreifen wollen warten. das würde das problem race condition imho lösen. und sicherheitsmäßig (sofern ich die eingaben escape - hab da von php böse dinge gehört/gelesen zb sql injection) sollte das doch auch keine probleme darstellen, oder? bleibt die frage der laufzeit - wobei dbms imho eh auf geschwindigkeit optimiert sein sollten?

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Glocke schrieb:

kannst du das mal bitte genauer ausführen? ich kann dir nicht ganz folgen.

Schau mal hier.

Glocke

(Themenstarter)
Avatar von Glocke

Anmeldungsdatum:
1. März 2009

Beiträge: 880

Wohnort: Thüringen

Lysander schrieb:

Glocke schrieb:

kannst du das mal bitte genauer ausführen? ich kann dir nicht ganz folgen.

Schau mal hier.

Wenn ich für mich und meine Konstruktion selber als Restriktion festlege, dass keine Objektinstanzen gespeichert werden können, wäre das Problem nicht existent. Oder sehe ich das falsch?

Beispielsweise

1
2
3
4
# data sei ein zweidimensionales dict und ich iteriere mittels i durch data
if (isinstance(data[i], object)):
	del data[i]
# und danach irgendwann den pickle-code zum speichern

*edit-push*

denkbar wäre auch das speichern der daten mittels mysql. wie sinnvoll ist das? optional in den datensatz ein "in bearbeitung"-flag rein, damit alle anderen prozesse die auf den datensatz zugreifen wollen warten. das würde das problem race condition imho lösen. und sicherheitsmäßig (sofern ich die eingaben escape - hab da von php böse dinge gehört/gelesen zb sql injection) sollte das doch auch keine probleme darstellen, oder? bleibt die frage der laufzeit - wobei dbms imho eh auf geschwindigkeit optimiert sein sollten?

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Glocke schrieb:

Wenn ich für mich und meine Konstruktion selber als Restriktion festlege, dass keine Objektinstanzen gespeichert werden können, wäre das Problem nicht existent. Oder sehe ich das falsch?

Insofern, als in Python alles ein Objekt ist!

Beispielsweise

1
2
3
4
# data sei ein zweidimensionales dict und ich iteriere mittels i durch data
if (isinstance(data[i], object)):
	del data[i]
# und danach irgendwann den pickle-code zum speichern

Wäre fatal, da jeder Eintrag gelöscht würde 😉

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
In [6]: isinstance(42, object)
Out[6]: True

In [7]: isinstance("hallo", object)
Out[7]: True

In [8]: def foo(): pass
   ...: 

In [9]: isinstance(foo, object)
Out[9]: True

*edit-push*

denkbar wäre auch das speichern der daten mittels mysql. wie sinnvoll ist das? optional in den datensatz ein "in bearbeitung"-flag rein, damit alle anderen prozesse die auf den datensatz zugreifen wollen warten. das würde das problem race condition imho lösen. und sicherheitsmäßig (sofern ich die eingaben escape - hab da von php böse dinge gehört/gelesen zb sql injection) sollte das doch auch keine probleme darstellen, oder? bleibt die frage der laufzeit - wobei dbms imho eh auf geschwindigkeit optimiert sein sollten?

RDMS bieten für so etwas Transaktionen, welche möglichst ACID sein sollten. Von Hand solltest / brauchst Du da nix basteln!

Glocke

(Themenstarter)
Avatar von Glocke

Anmeldungsdatum:
1. März 2009

Beiträge: 880

Wohnort: Thüringen

Lysander schrieb:

Glocke schrieb:

Wenn ich für mich und meine Konstruktion selber als Restriktion festlege, dass keine Objektinstanzen gespeichert werden können, wäre das Problem nicht existent. Oder sehe ich das falsch?

Insofern, als in Python alles ein Objekt ist!

Ähm ich konkretisiere meine Aussage: Instanzen EIGENER Objektdefinitionen.

Beispielsweise

1
2
3
4
# data sei ein zweidimensionales dict und ich iteriere mittels i durch data
if (isinstance(data[i], object)):
	del data[i]
# und danach irgendwann den pickle-code zum speichern

Wäre fatal, da jeder Eintrag gelöscht würde 😉

ups - eben mitbekommen xD

denkbar wäre auch das speichern der daten mittels mysql. wie sinnvoll ist das? optional in den datensatz ein "in bearbeitung"-flag rein, damit alle anderen prozesse die auf den datensatz zugreifen wollen warten. das würde das problem race condition imho lösen. und sicherheitsmäßig (sofern ich die eingaben escape - hab da von php böse dinge gehört/gelesen zb sql injection) sollte das doch auch keine probleme darstellen, oder? bleibt die frage der laufzeit - wobei dbms imho eh auf geschwindigkeit optimiert sein sollten?

RDMS bieten für so etwas Transaktionen, welche möglichst ACID sein sollten. Von Hand solltest / brauchst Du da nix basteln!

Was zusätzliches basteln meinte ich jetzt nicht - eher ne Schnittstelle die sich "anfühlt" als wäre es ne Session, das Zeug aber heimlich in die Datenbank wirft ^^

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Glocke schrieb:

Was zusätzliches basteln meinte ich jetzt nicht - eher ne Schnittstelle die sich "anfühlt" als wäre es ne Session, das Zeug aber heimlich in die Datenbank wirft ^^

Ja, und dafür gibt es eben Transaktionen bei DBs 😉 Du schriebst ja was von "Flag" und das ist nun einmal nicht notwendig, bzw. würde sogar eher noch falsche Tatsachen vorgaukeln.

Antworten |