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
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)
Anmeldungsdatum: 1. März 2009
Beiträge: 880
Wohnort: Thüringen
|
Du darfst diesen Beitrag nicht bearbeiten!
zurück zum thema 😀
|
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
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)
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
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
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
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)
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
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)
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 | # 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
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 | # 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 😉
| 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)
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 | # 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
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.
|