[Bottle] Cookie-basierte Nutzer-Authentifizierung

Django, Flask, Bottle, WSGI, CGI…
Antworten
Benutzeravatar
noisefloor
User
Beiträge: 2784
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: Görgeshausen
Kontaktdaten:

Montag 16. August 2010, 13:47

Hallo,

im folgende eine (rel. einfache) Nutzer-Authentifizierung via Bottle via Cookie:

Code: Alles auswählen

import bottle
from hashlib import md5

userdict = {
'OttoNormal':'7\xfc~\xde\xe2Z\x17tt\xea\xeb\xe7\xf7\xb0\x97\x85',\
'RainerTitan':'>\xb3\x8f\xa8\x07\x9f\x88s$\xe8\xee\x1d\x92\xb3\xda\x12',\
'VolkerRacho':'1\xd4T\x1b\x8e\x92j$\xf0\xc9\xb85\xb6\x8c\xfd\xf3'}
#userdict = {'OttoNormal':'flat','RainerTitan':'steel','VolkerRacho':'fast'}

@bottle.route('/start')
def start():
    return '<a href="/public">Public Page</a> or go to <a href="/login">Log-in</a>'

@bottle.route('/public')
def public():
    return 'This is a public page'

@bottle.route('/login')
def login():
    return '''<html>
    <form action="/checklogin" method="POST">
    Name: <input type="text" name="user" length="20">
    Password: <input type="password" name="passw" length="20">
    <input type="submit" value="send">
    </html>'''

@bottle.route('/checklogin', method='POST')
def checklogin():
    if not bottle.request.forms.get('user'):
        return 'Go to log in page first!'
    user = bottle.request.forms.get('user')
    passw = bottle.request.forms.get('passw')
    if user not in userdict:
        return bottle.template('Sorry, the user {{user}} is not registered here!', user=user)
    elif md5(passw).digest() != userdict[user]:
        return 'Wrong password!'
    else:
        bottle.response.set_cookie('user',user,secret='arealsecret')
        return bottle.template('You are logged in now, user {{user}}', user=user)

@bottle.route('/secretpage')
def secretpage():
    try:
        user = bottle.request.get_cookie('user',secret='arealsecret')
    except:
        user = None
    if not user:
        return 'Log in first!'
    else:
        return 'This is a secret page :-)'

bottle.debug(True)
bottle.run(reloader=True)
Funktioniert auch so. Da ich auf dem Gebiet aber eher wenig Erfahrung habe: Ist das so ok oder gibt es irgendwelche Schwachstellen?

Gruß, noisefloor
Benutzeravatar
noisefloor
User
Beiträge: 2784
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: Görgeshausen
Kontaktdaten:

Montag 16. August 2010, 14:14

Hallo,

Nachtrag:

Bei einer "realen" Applikation würde die Speicherung von user und password in einer DB erfolgen, nicht via hard-coded dict

Außerdem würden dann noch die Cookie-Option "discard" gesetzt.

Gruß, noisefloor
Benutzeravatar
noisefloor
User
Beiträge: 2784
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: Görgeshausen
Kontaktdaten:

Sonntag 22. August 2010, 19:13

Hallo,

niemand? Gut, dann scheint es perfekt zu sein. :D

Schreibe das ganze jetzt noch auf Authentifizierung gegen SQLite um, ein bisschen Text dazu - dann kann es in die Bottle-Doku, wenn Defnull möchte.

Gruß, noisefloor
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Sonntag 22. August 2010, 19:26

Verbesserungswuerdig. Als erstes, ist request.form soweit ich weiss ein normales dict oder was in der Richtung, get() wird also bei fehlenden Daten ein None liefern und damit einen 500 internal server error. Bad idea because server errors usually cause extra IO because they end up in a logfile. That gives people the ability to do damage to the server with a bit of effort. Use get(key, '') instead when do use Bottle.

Dann gilt natuerlich wie fuer alles, dass md5 ohne salting gefaehrlich ist. Klau dir Werkzeug's generate_password_hash / check_password_hash Funktionen.

Ein "except:" in einer Serveranwendung ist eine sehr schlechte Idee, weils Signals verschluckt. Lieber "except Exception:" machen.
TUFKAB – the user formerly known as blackbird
Benutzeravatar
noisefloor
User
Beiträge: 2784
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: Görgeshausen
Kontaktdaten:

Sonntag 22. August 2010, 20:51

Hallo,

ok, thx. :-)
Ein "except:" in einer Serveranwendung ist eine sehr schlechte Idee, weils Signals verschluckt. Lieber "except Exception:" machen.
Ah, ok. Wusste ich nicht. Für mein Verständnis: "except" und "except Exception" sind am lange Ende das gleicher, weil alle Exception abgefangen werden? Nur "except Exception" ist aus den o.g. Gründen sicherer / "bullet-proof"?

Gruß, noisefloor
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Sonntag 22. August 2010, 21:59

Beispiel:

Code: Alles auswählen

In [1]: issubclass(ValueError, Exception)
Out[1]: True

In [2]: issubclass(KeyboardInterrupt, Exception)
Out[2]: False
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
metty
User
Beiträge: 99
Registriert: Samstag 13. Dezember 2008, 19:30

Freitag 17. September 2010, 16:41

@noisefloor
Ah, schön zu sehen, das noch jemand den gleichen Gedanken hatte ;)
Ich bin grad dabei, bzw. wenn ich mal wieder ein wenig freie Zeit habe, ein Auth-System, für bottle zu schreiben.
Das ganze soll ähnlich wie bei Rails oder Tornado mit HMAC verschlüsselten Cookies funktionieren. Diese Lösung müsste (was man so hört) "relativ" sicher gegen Manipulation des Cookie sein.
Benutzeravatar
noisefloor
User
Beiträge: 2784
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: Görgeshausen
Kontaktdaten:

Freitag 17. September 2010, 19:13

Hallo,

habe vor ein paar Wochen, basierend auf dem obigen Beispiel, ein Version an Defnull für die Doku geschickt. Schau mer mal, ob er aus aufnimmt. :-)

Gruß, noisefloor
Antworten