Dear Flask, Please Fix Your “Secure” Cookies
stacksmashing.net
stacksmashing.net
Unless the data is really simple and you don't care if it's stolen, session data should always be stored on the server side, and only a meaningless identifier sent to the client.
Managing sessions on the server side used to be a PITA, to be sure, especially if you had multiple servers. But nowadays there are lightening-fast distributed key-value stores that are ideal for storing session data. No need to encrypt, base64-encode, base64-decode, and decrypt multiple kilobytes of data with every request. Think of all the bandwidth and latency you could save by not sending those kilobytes back and forth!
First of all they are not encrypted, they have a MAC. Secondly because you can verify the basic information of the request without hitting a database which is very convenient. In fact if it would not be for signed cookies Flask would not have any sessions because it does not dictate a data store. However you can easily change that: http://flask.pocoo.org/snippets/75/
> Think of all the bandwidth and latency you could save by not sending those kilobytes back and forth!
You are not saving anything there. A session should really only contain user id.
So it looks like Flask is using something that just deliberately runs pickled strings. Even if I know my own secret key, I don't exactly need to be able to send myself arbitrary code. So JSON seems to make sense to me for my use cases.
pickle.loads("cos\nsystem\n(S'whoami'\ntR.")
Right.. so anyway, does anyone know which session engine I want to use with Flask if I want to generate a token for a user's session, which I can then later revoke if I end up hating that user's session but not two other sessions?It should be noted that the maintainer knows this, but has commented that he cannot change the default to json because folks are still storing non-json-safe data.
This is the right decision (for now). Otherwise, we'd see a "flask just broke everyone's apps" story on the front page.
This is all ours do. I'm not totally clear on where the actual security issue is here. Adding a level of indirection to a backend store doesn't seem like it would change much.
Obscuring through an opaque token of suitable entropy means that it is effectively impossible to guess a valid token. Accepting the client's idea of who the user is is playing with fire.
"Lightning fast" is still a lot slower than no lookup at all.
A few bytes of cookie cost next to nothing in terms of bandwidth nor latency and can save a lot of hardware on the backend for large sites.
If you use encryption and an HMAC to harden up said cookie, you need to a) not bugger up your scheme and b) pay the overhead the calculations. For the HMAC it's trivial, but ciphers are a bit more involved.
AES overhead is a non-issue for all but the very largest sites. A modern CPU can pipe north of 100MB/sec through AES - it's very unlikely to become the bottleneck in a python web-app.
You can store data in cookies without using a potentially unsafe serialization scheme. Baby != Bathwater.
Might someone adapt Beaker's secure cookie session into its own pypi package and include a flask adapter with it? It's time we all got behind a best practice for sessions (which IMHO should be cookie based, encrypted, and very small/only basic identiication with more significant data stored in the DB).
To some extent, they may have been correct: if you look at the relative complexity of HTTP header fuzzing or a SQL injection attack compared to finding 0day in, say, the Linux kernel, it's generally not even a contest.
That said, exploits like this demonstrate the carelessness that can go into many applications and frameworks on the web. In my years of application security, I've seen some "interesting" vulnerabilities like this, but I've seen thousands of people with standard, well-known security problems all over their applications.
"Broken Authentication & Session Management" is an extremely common finding for my team to write up. People think that, oh, we don't need this cookie to be marked Secure or HTTPOnly. "If the browser's owned, we're screwed anyway."
The problem with this uninformed stance on application security is that exploits do not always need to stand on their own to introduce a significant level of risk. For example, should a cookie not be marked HTTPOnly, the browser itself does not need to be compromised. Simple cross-site scripting (another extremely common issue in webapps) can easily access these cookies and throw them at malicious receivers.
This is just one example, but like the article referenced in the original post, it seems to me that some people just don't take security seriously.
That said, the research referenced here is pretty cool -- for those of you that missed it, you can read the Black Hat 2011 paper on this issue here: http://media.blackhat.com/bh-us-11/Slaviero/BH_US_11_Slavier...
In fact the python-openid extension is the most common offender. Also I can't just switch the default because it would invalidate everyone's currently issued sessions.
The issue is not new, changing it without breaking things is the hard part.
It does nothing for the pickle issue but it's quite a shame to send cookies in plain-text in this day and age.
They are currently on a separate branch and they are known to break python-openid (and with that Flask-OpenID). I don't have a solution for that yet. If someone is really concerned regarding security you can copy/paste the code into your own project. The session interface in Flask is pluggable for a while already.
Allows for any size/types of data but the worst case scenario-without code execution is that an attacker hijacks an existing but valid session.
It is not a complete solution, as an attacker could still DoS your service by making pickle allocate a huge amount of memory, but at least that's better than allowing arbitrary code execution.
For example I developed a protocol with hash-chaining and HMACs for messages. I have two keys: one for performing the hash-chain calculation, and a different key for the HMAC of the one time message.
Could I have used a single key? Absolutely, yes. But the time it takes to perform both is trivial. And I've bought myself a little extra protection from any attacks that reveal a few bits of a key, because gathering a bit here and there of different keys won't help my attacker as much as gathering bits for the a universal key being used for everything.
Attacks often involve multiple rounds of escalation as people keep on increasing their level of access. You want that escalation to be as hard as possible. Therefore you really don't want there to be a fact that could be floating around your organization in various ways that can be used to go straight to executing arbitrary code on your production site.