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.
Answer from Thomas Orozco on Stack OverflowThe 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.
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.
I remember it being not secure to use the default flask session a few years back. Is that still the case?
I've been working on a small Flask web app with a basic user login system, and I'm getting a little paranoid about security. I've read about a few common vulnerabilities and I want to make sure I'm doing things right before I get too far along. My app connects to a MySQL database and uses Flask's built-in sessions for user authentication. I've read that session cookies should be set to Secure=true and HttpOnly=true to prevent certain attacks, which I've done. I'm also using parameterized queries to prevent SQL injection, which I know is a huge deal. My main concern is session management, particularly issues like session fixation and brute-force attacks . I'm wondering if a simple login system is enough, or if I need to be more proactive. I want to protect user credentials and prevent unauthorized access. How do you guys handle things like locking out users after multiple failed login attempts? What are your go-to security best practices for production-level Flask applications? Any advice on how to ensure my app is secure before it goes live would be a huge help.
I'm in the final state of my first Flask app and i'm trying to make sure that it has the security necessary to protect the users and their information. It's a simple platform where users can register/login/logout and make posts. I'm using Flask-Login for logging in the users and storing the data (username, email, password) in a SQL database using SQLAlchemy and for the forms i'm using Flask-WTF. The thing is, yesterday i found out about how Flask handles session cookies and that they're signed but not encrypted, so they shouldn't contain any secret information and here's my concern: When decoding and analyzing the session cookie in various scenarios, i found some information that i'm not sure if should be there or not.
For example, when logged in, the cookie stores the user's id which is the id of the user in the database. Though I read on an article and video from Miguel Grinberg (see comment #11) about it and now i know that having the user's id on the cookie may not be an issue, i don't know how that id got in there, because i didn't write any code to put it in the session or anything.
Another thing that i see stored in the cookie when i access the login route, login and then logout, there is now another element in the cookie which is the csrf_token (i'm using flask-wtf to make the forms and making use of the form.hidden_tag() ). It first appears in the cookie when i access the login route/form, and it stays in the cookie all the time the user is logged in, and even when logged out, the cookie still has that element. I don't know if it's OK to have the csrf token on the cookie, and if it's not, I don't know how to not include it either, because as I said with the user Id, i didn't write any code to include the csrf_token in the cookie, so i don't really know what is including it there.
To illustrate you better, here is the content of the cookie in the various scenarios i talk about:
NOTE: the IP Address is included by me, which is the only element i explicitly wrote code to include in the session. Not the cookie but the session.
when accesing the website @ localhost:5000, session cookie contains this information:
{
"_fresh": false,
"user_ip": "127.0.0.1"
}
when accesing login route, session cookie contains now this information (should this csrf_token be here?):
{
"_fresh": false,
"csrf_token": "10106b35c897dfd877367f68a8924761239c7ddd",
"user_ip": "127.0.0.1"
}
when loggin in, session cookie now contains this information:
{
"_fresh": true,
"_id": "a1a2a05700b69fb7a02745a1c87d131168cc1d5a0173e222e402bd334d9e1b6
a9fa2ac7bfbfe325e7b04eb9b852f5a39e396eab8a2c333ecff36c698f80f9de8",
"_user_id": "1", #this is the user id in the database
"csrf_token": "10106b35c897dfd877367f68a8924761239c7ddd",
"user_ip": "127.0.0.1"
}
when logged out, session cookie contains this information:
{
"_fresh": false,
"csrf_token": "10106b35c897dfd877367f68a8924761239c7ddd",
"user_ip": "127.0.0.1"
}If you can help me with any tips or any information about if this is an issue and how can i resolve, and how could i improve the security of the website i would really appreciate it. If you have any questions or don't really understand what i'm talking about in this post, let me know.