While looking for a good and efficient way to have a session in my app, I found GAE Boilerplate and GAE Sessions.
GAEB is amazing but very vast for my needs: I don't need Federate Login nor a default User structure, but I like the design structure and the way they solved some issues (routes, forms,...).
GAES is quite simple but powerfull to treat sessions. The most I like is the way it stores everything in a cookie, in this case, it stores the full user entity in a cookie so in the next page calls, no other datastore hits are done: the user data is always read from the cookie (this need, obviusly to update the data if the user updates something, which is not usual).
In the other hand, GAEB stores only the user ID and then retrieves, on each page call, the username and the user email. This is part of the code for the BaseHandler it uses (GAEB uses NDB model):
#webapp2.cached_property
def username(self):
if self.user:
try:
user_info = models.User.get_by_id(long(self.user_id))
if not user_info.activated:
self.auth.unset_session()
self.redirect_to('home')
else:
return str(user_info.username)
except AttributeError, e:
# avoid AttributeError when the session was delete from the server
logging.error(e)
self.auth.unset_session()
self.redirect_to('home')
return None
Same for email, and in the render_template function it does this:
def render_template(self, filename, **kwargs):
.... some code.....
# set or overwrite special vars for jinja templates
kwargs.update({
'app_name': self.app.config.get('app_name'),
'user_id': self.user_id,
'username': self.username,
'email': self.email,
... more vars ...
})
kwargs.update(self.auth_config)
It seems that reads 2 times (one for username and one for email) from the datastore, because this funcs makes models.User.get_by_**field**(long(self.user_id))
The only thing I don't know exactly what means is the #webapp2.cached_property, that maybe means that all this datastore reads are done from a cache and really don't hit the datastore.
Can someone tell me what is the better solution to save hits to the database? It seems that it is better to have all the user data in a cookie (obviously, secured) and don't hit the datastore on every page call, but maybe I'm mistaken (I'm relatively noob with GAE) and all this reads to datastore are cached and, then, for free.
Saving session data in the cookie is highly discouraged:
It has to be transfered with each request (slow on mobile connections)
The HTTP Header size you can transfer to the GAE is limited (64Kb if i remember correctly) - thats the upper bound of data you could store
Even if you encrypt and sign your session, you would still be vulnerable to reply attacks (you cannot perform a logout safely)
I don't know the implementations you mentioned, but we have an session implementation in our CMS, see https://bitbucket.org/viur/server/src/b2e9e3dca3adabee97e1761d630600a387a02c44/session.py?at=master .
The general idea is to generate a random string (used as a session identifier).
On session load a datastore "get by key" is performed (which is cached, so if that object is still in memcache, it wont hit the datastore at all).
And saving is only performed if the data stored inside the session changed or the session has not been
updated for the last 5 minutes.
Then you can copy the values of your user object into the session and wont have an additional datastore request.
Related
I'm trying to implement a logic in my Flask application to prevent reply attacks.
Regarding to the question asked here, My idea is to set the current session lifetime when user logs out from the system. In general, it is suggested to set the session lifetime this way:
#app.before_request
def before_request():
session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=10)
However, I want to set my current session life time when user logs out from the system. Something like the following code:
#app.after_request
def app_after_request(response):
response.headers["X-Frame-Options"] = "SAMEORIGIN"
if "__logged_out__" in session and session["__logged_out__"] is True:
session.clear()
response.set_cookie(app.session_cookie_name, '', expires=0)
return response
I also checked this question, but the problem is that I'm dealing with some confidential data and I have to ensure that session is cleared after user logged out from the system. Is there any way to set one session lifetime after creation manually? or is there any easy way to handle this situation with flask-login?
I found the solution. I should simply use Flask-KVSession package to store session data in database (or any other data storage) instead of server memory. As the package website introduced:
Flask-KVSession is an MIT-licensed server-side session replacement for
Flaskās signed client-based session management. Instead of storing
data on the client, only a securely generated ID is stored on the
client, while the actual session data resides on the server.
You also need to create a key-value paired table in your database (it has named sessions by default, but you can change the name and schema as well) and point it to your flask app object. More information can be found here.
How do I create a new clean session and invalidate the current one in Flask?
Do I use make_null_session() or open_session()?
I do this by calling session.clear().
EDIT:
After reading your comment in another answer, I see that you're trying to prevent a replay attack that might be made using a cookie that was issued in the past. I solved that problem as much as possible* with this approach:
Override SecureCookieSessionInterface.save_session(), copying the code from the overridden version rather than calling it.
When the overridden version of save_session() calls save_cookie(), make it pass a session_expires argument 30 minutes in the future. This causes cookies more than 30 minutes old to be considered invalid.
Make the overridden version of save_session() update a session variable every so often, to make sure the cookie and its session_expires time get rewritten regularly. (I name this session variable '_refresh' and store the current time in it, then rewrite it only if more than a few seconds have passed since the last-stored time. This optimization avoids rewriting the cookie on every HTTP request.)
Duplicating Flask code in the custom save_session() makes this approach a bit ugly and brittle, but it is necessary in order to change the arguments passed to save_cookie(). It would be nice if Flask made this easier, or at least implemented its own safeguard against replay attacks.
*WARNING: This approach by itself will not stop replay attacks that might happen during a session cookie's valid lifetime. This fundamental problem with cookie-based sessions is discussed in RFC 6896 and A Secure Cookie Protocol by Liu, Kovacs, Huang, Gouda.
If you have security concerns (and everyone should have) There is the answer:
This is not REALLY possible
Flask uses cookie-based sessions. When you edit or delete session, you send a REQUEST to CLIENT to remove the cookie, normal clients (browsers) will do. But if session hijacked by an attacker, the attacker's session remains valid.
You can add an after_request callback to remove the session cookie if a particular flag is set:
#app.after_request
def remove_if_invalid(response):
if "__invalidate__" in session:
response.delete_cookie(app.session_cookie_name)
return response
Then you simply set that session key whenever you want to invalidate the session:
#app.route("/logout")
def logout():
session["__invalidate__"] = True
return redirect(url_for("index"))
See also: http://werkzeug.pocoo.org/docs/wrappers/#werkzeug.wrappers.BaseResponse.delete_cookie
If you use default flask sessions and set the app.permanent_session_lifetime, then the session will not work if a user tries to replay the same session as long as the session has expired.If you look at the source code for open_session, there is line:
max_age = total_seconds(app.permanent_session_lifetime)
try:
data = s.loads(val, max_age=max_age)
return self.session_class(data)
except BadSignature:
return self.session_class()
I'm using pyramid web framework. I was confused by the relationship between the cookie and session. After looked up in wikipedia, did I know that session is an abstract concept and cookie may just be an kind of approach (on the client side).
So, my question is, what's the most common implementation (on both the client and server)? Can somebody give some example (maybe just description) codes? (I wouldn't like to use the provided session support inside the pyramid in order to learn)
The most common implementation of sessions is to use a cookie.
A cookie provides a way to store an arbitrary piece of text, which is usually used as a session identifier. When the cookie gets sent along with a HTTP request, the server (technically the code running on it) can use the cookie text (if it exists) to recognise that it has seen a client before. Text in a cookie usually provides enough information to retrieve extra information from the database about this client.
For example, a very naive implementation might store the primary key to the shopping_cart table in a database, so that when the server receives the cookie text it can directly use it to access the appropriate shopping cart for that particular client.
(And it's a naive approach because a user can do something like change their own cookie to a different primary key and access someone else's cart that way. Choosing a proper session id isn't as simple as it seems, which is why it's almost always better to use an existing implementation of sessions.)
An alternate approach is to store a session identifier is to use a GET parameter in the url (for example, in something like http://example.com/some/page?sid=4s6da4sdasd48, then the sid GET param serves the same function as the cookie string). In this approach, all links to other pages on the site have the GET param appended to them.
In general, the cookie stored with the client is just a long, hard-to-guess hash code string that can be used as a key into a database. On the server side, you have a table mapping those session hashes to primary keys (a session hash should never be a primary key) and expiration timestamps.
So when you get a request, first thing you do is look for the cookie. If there isn't one, create a session entry (cookie + expiration timestamp) in the database table. If there is one, look it up and make sure it hasn't expired; if it has, make a new one. In either case, if you made a new cookie, you might want to pass that fact down to later code so it knows if it needs to ask for a login or something. If you didn't need to make a new cookie, reset the expiration timestamp so you don't expire the session too soon.
While handling the view code and generating a response, you can use that session primary key to index into other tables that have data associated with the session. Finally, in the response sent back to the client, set the cookie to the session key hash.
If someone has cookies disabled, then their session cookie will always be new, and any session-based features won't work.
A session is (usually) a cookie that has a unique value. This value maps to a value in a database or held in memory that then tells you what session to load. PHP has an alternate method where it appends a unique value to the end of every URL (if you've ever seen PHPSESSID in a URL you now know why) but that has security implications (in theory).
Of course, since cookies are sent back and forth with every request unless you're talking over HTTPS you are sending the only way to know (reliably) that the client you are talking to now is the same one you logged in ten seconds ago to anyone on the same wireless network. See programs like Firesheep for reasons why switching to HTTPS is a good idea.
Finally, if you do want to build your own I, was given some advice on the matter by a university professor. Give out a new token on every page load and invalidate all a users tokens if an invalid token is used. This just means that if an attacker does get a token and logs in to it whilst it is still valid when the victim clicks a link both parties get logged out.
I'm using an existing database for my latest Django project, so unless I change my Models or the Django auth code, it's going to be rather difficult to merge the two.
Rather than messing with the existing auth backend, I'm planning on just writing my own authentication app.
Anyway, all of my previous authentication apps have been written in PHP, where basically i just throw everything in session variables and verify them on every page... Here's what I'm a bit confused about. It appears that when a user is authenticated/logged in, the entire user is added to a session, but I can't figure out where or how that is occurring.
In the default Django login function, it's assigning user to request.user ... is this being saved as a session variable somehow or is it just passed into the next view? If it is just being passed to the next view, how are future requests authenticated without requiring further login requests?
The default Django auth login is below..
def login(request, user):
"""
Persist a user id and a backend in the request. This way a user doesn't
have to reauthenticate on every request.
"""
if user is None:
user = request.user
# TODO: It would be nice to support different login methods, like signed cookies.
if SESSION_KEY in request.session:
if request.session[SESSION_KEY] != user.id:
# To avoid reusing another user's session, create a new, empty
# session if the existing session corresponds to a different
# authenticated user.
request.session.flush()
else:
request.session.cycle_key()
request.session[SESSION_KEY] = user.id
request.session[BACKEND_SESSION_KEY] = user.backend
if hasattr(request, 'user'):
request.user = user
user_logged_in.send(sender=user.__class__, request=request, user=user)
I also tried to follow the user_logged_in.send(), which is in django.dispatch.dispatcher.send but I'm not entirely sure what that's supposed to do either.
def send(self, sender, **named):
"""
Send signal from sender to all connected receivers.
If any receiver raises an error, the error propagates back through send,
terminating the dispatch loop, so it is quite possible to not have all
receivers called if a raises an error.
Arguments:
sender
The sender of the signal Either a specific object or None.
named
Named arguments which will be passed to receivers.
Returns a list of tuple pairs [(receiver, response), ... ].
"""
responses = []
if not self.receivers:
return responses
for receiver in self._live_receivers(_make_id(sender)):
response = receiver(signal=self, sender=sender, **named)
responses.append((receiver, response))
return responses
Basically what I'm looking for is for someone to explain an efficient way to save user session data in Python that does not depend on the Django framework. A little run-through of the Django authentication would be nice as well.
HTTP is stateless; regardless of the server used, the framework or language, there is no intrinsic way for an HTTP client to say "this request is part of that session". That's part of the design of HTTP.
So sessions are always a feature of the web application; either supported by the a web app framework or implemented in the app itself. The most usual way for a stateful session to be created from the stateless protocol is with cookies; Clients will store cookies at the request of a server and return those same cookies to that server in future requests.
Session data can be serialized and stored in the cookie itself, but that's both insecure (secret information could be forged or eavesdropped), and inefficient (takes bandwidth even though the individual bytes are of no use to the client), and so the preferred solution is to use an opaque (and even better, single use) session key is stored in a cookie, and the web application will store session data out of band; either in memory, in the filesystem, or a database backend, or some other option.
django takes care of most of this transparently in "middleware", modules that modify incoming requests and outgoing responses. The auth middleware will read a cookie and check if that represents a logged in user, and if so, add a user object to the request; it also attaches cookies to responses when a user gets logged in. the session middlware works in a similar fashion, checking for a cookie, and reading the session data from wherever it was stored between requests, and also grabbing session data from responses and storing them, along with setting a cookie to associate the client's session with the session data it just stored.
Since both of these features are useful, independent of each other (I tend to avoid sessions, but usually use some kind of authentication), they do not depend on each other. Session-like authentication is implemented in a similar manner as sessions, but authenticated users are not stored in "The Session", nor are sessions attached to "The authenticated User".
You might not think so, but django's authentication system is designed to be extended; if you already have a database of valid users you'd like to authenticate against, it's very simple to add a new auth backend that dovetails neatly into the standard django auth application (which means you can also use other applications that depend on it in turn).
I'm building an application in which the client pings the server every now and then (let's not get into why). When the server handles these requests, it checks whether the client is logged in or not using request.user.is_authenticated()
It looks something like this:
def handle_ping_request(request):
if request.user.is_authenticated():
# Do something...
else:
# Do Something else...
I've noticed that sometimes the server receives a log-in request immediately followed by a ping request (from the same user). The client is then successfully logged-in, the response returns with a new session ID (of the logged in user) and (I guess that) the old session-ID (of the anonymous user) is removed. When the ping request is processed, its request contains the old session-ID. Thus the ping request returns with a third session ID and on the next request the client makes, the client is no longer logged in.
My log-in code looks something like:
if not request.user.is_authenticated():
user = auth.authenticate(...credentials...)
if user and user.is_active:
auth.login(request, user)
Do you have any suggestions on how to avoid this problem? Preferably without involving the client.
Thanks.
It's probably too messy to handle this on the server because you'll have to create some kind of a semaphore system that will also try to guess if any ping is currently from a client that is also being authenticated. My suggestion would be simply to change the client code not to ping while it's waiting for a response to its login request.
You could create an alternative to the standard contrib.auth.login method that keeps the same session id, rather than generating a new one, either by using a custom authentication backend that doesn't generate a new key, or by creating a custom session backend that overrides the cycle_key() method in contrib.sessions.base to reuse the same key.
BUT: think about what you might be opening yourself up to by reusing the same session key - depending on where this system is in use, you'd be making yourself more open to session hijacking (ie: there's only one session id to sniff), as well as potentially issues where caches may return the unauth page content instead of the auth page content because the sessionid is technically the same and the cache can't tell the difference between the two situations, etc, etc, etc.
In short: there's a reason it's built to work, by default, the way it does.