Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly and securely handle cookies and sessions in Python's Flask?

In application I am writing at the moment I've been saving in users browser a cookie that had session ID stored inside, and that ID was used as a reference to a session stored in the database containing user's information including the fact if the user is logged in properly.

I wanted to review the security of my solution and I stared to look into how I should be setting up cookies upon login, what to store in server side stored session and how to destroy that information on logout since as of now my users were staying logged in for ages, which was not my intention.

The problem I have is no definite answer on how to handle the whole user login/session/logout issue properly in Flask - some people are talking about using Flask's Response.delete_cookie() function, others to expire it using .set_cookie() with zero expiration time, others are mentioning Flask's session module, other itsdangerous module...

What is the most secure, right and proper way of handling that in terms of modules that should be used with Flask, code examples and so on?

like image 997
SpankMe Avatar asked Dec 01 '13 17:12

SpankMe


People also ask

Is flask session cookie secure?

Flask cookies should be handled securely by setting secure=True, httponly=True, and samesite='Lax' in response. set_cookie(...). If these parameters are not properly set, your cookies are not properly protected and are at risk of being stolen by an attacker.

How do I use session cookies in Flask?

Flask cookies In Flask, set the cookie on the response object. Use the make_response() function to get the response object from the return value of the view function. After that, the cookie is stored using the set_cookie() function of the response object.

How do I secure a session cookie?

You can secure a session cookie by setting an expiration, only allowing encrypted network transmission, blocking third party with the Httponly flag, and configuring where it is stored.

How do you handle cookie-based sessions?

Because it is a stateless protocol, sessions must be managed between the browser side and the server side. With cookie-based session management, a message (cookie) containing user information is sent to the browser by the web server. This cookie is sent back to the server when the user tries to access certain pages.


2 Answers

The background

Method #1

An easy and safe way to handle sessions is to do the following:

  • Use a session cookie that contains a session ID (a random number).
  • Sign that session cookie using a secret key (to prevent tempering — this is what itsdangerous does).
  • Store actual session data in a database on the server side (index by ID, or use a NoSQL key / value store).
  • When a user accesses your page, you read the data from the database.
  • When a user logs out, you delete the data from the database.

Note that there are a few drawbacks.

  • You need to maintain that database backend (more maintenance)
  • You need to hit the database for every request (less performance)

Method #2

Another option is to store all the data in the cookie, and sign (and optionally encrypt) said cookie. This method, however, has numerous shortcomings too:

  • This is easier on the backend (less maintenance, better performance).
  • You need to be careful to not include data your users should not see in sessions (unless you're encrypting).
  • The volume of data you can save in a cookie is limited.
  • You can't invalidate an individual session (!).

The code

Flask actually implements signed session cookies already, so it implements method #2.

To get from #2 to #1, all you have to do is:

  • Generate random Session IDs (you could use os.urandom + base64).
  • Save session data in a database backend, indexed by Session ID (serialize it using e.g. JSON, Picke if you need Python objects, but avoid if you can).
  • Delete sessions from your database backend when a user logs out.

Make sure you're protected against session fixation attacks. To do so, make sure you generate a new session ID when a user logs in, and do not reuse their existing session ID.

Also, make sure you implement expiration on your sessions (just a matter of adding a "last-seen" timestamp).

You could most likely get some inspiration from Django's implementation.

like image 160
Thomas Orozco Avatar answered Sep 30 '22 18:09

Thomas Orozco


I would recommend you go with the Flask KVSession plugin with the simplekv module to persist the session information.

Conceptually, Flask KVSession provides an implementation for Method #1 described above using the Flask session interface. That way you don't have to alter your code to get it running, and you can use the extension methods to do additional things such as session expiration. It also takes care of the session signing, and does some basic checks to prevent tampering. You will still want to do this over HTTPS to absolutely prevent session stealing however.

Simplekv is the actual module that handles the writing and reading to various data storage formats. This can be as simple as a flat file, as fast as Redis, or as persistent as a database (NoSQL or otherwise). The reason this is a separate module is so Flask KVSession can just be a plain adapter to Flask without having to know about the storage mechanism.

You can find code samples at http://flask-kvsession.readthedocs.org/en/latest/. If you need more examples, I can provide one.

Alternatively, if you need a more enterprise and heavyweight server sided implementation for Flask, you can also look at this recipe using Beaker which works as WSGI middleware (meaning other frameworks also use it). http://flask.pocoo.org/snippets/61/. The Beaker API is at http://beaker.readthedocs.org/en/latest/.

One advantage Beaker provides over Flask KVSession is that Beaker will lazy load sessions, so if you don't read the session information, it won't make a connection to the database on every call. However, Beaker depends on SQLAlchemy which is going to be a larger module than simplekv module.

Unless that specific performance case is important, I would still go with Flask KVSession because of its slightly simpler API and smaller code base.

like image 43
Wulfram Avatar answered Sep 30 '22 20:09

Wulfram