I just do not understand why we keep persisting in putting session data into cookies.
Its between hard and impossible to build to systems perfectly that do this, whereas a server based lookup has a limited number of attacks that do not involve owning my boxes.
I have even written my own session handling wsgi middleware just because I don't understand encryption and cannot find a framework that doesn't try that.
I believe the whole purpose of putting session data into cookies is to prevent the other issues that arise when storing session data on the server's database. The main issue is that when you're load balancing, each request could be load balanced to a different server, so you need the session to be stored on the client side to prevent the hassle of trying to scale your back-end to use your solution.
> I believe the whole purpose of putting session data into cookies is to prevent the other issues that arise when storing session data on the server's database. The main issue is that when you're load balancing, each request could be load balanced to a different server,
When you are load balancing, request 1 goes to web/app server 1, the app server reads the session id from the cookie and read the session from the db..the next request goes to web server 2, web server 2 reads the session id from the cookie, loads the session from the db...
Each request being load balanced to a different web/app server doesn't affect the session. You are going to read the session id from the signed cookie, and then load the session from the db which is being shared between all of your web/app servers.
you assume that the load balancing doesn't balance across db's as well. I assume if your app needed load balancing, there is justification to shard it across different DBs too.
> I assume if your app needed load balancing, there is justification to shard it across different DBs too.
Having 2 or more web/app servers sharing a db is a very common setup. Db sharding is more of an exception than a norm.
Even then, db sharding doesn't affect sessions unless your sharding parameter is if the request is on web server 1, then load from shard 1(which doesn't make any sense). The code which decides which shard to query is common on all web servers and it will hit the required shard regardless.
Or use sticky sessions and keep the session state server side... Much faster than rebuilding session state for every request (whether from a cookie or from a DB), especially the more complex your app and session state become.
In my experience, sticky sessions open a whole new can of worms. With proxies and VLAN, it's very easy to have an extremely unbalanced load if you use naive IP-based balancing. If one of the servers becomes a "hot spot", adding more servers won't immediately remove the load from that. And when a server dies, the sessions in that server are lost. These problems can be mitigated with an in-memory distributed database overlaid on top of your cluster, but that opens its own can of worms...
Apache and nginx both have an array of good LB algos. I've never seen IP-based LB or hot-spots really. Most app servers support session replication/backup to other node(s). This is really standard stuff in JBoss for instance (my world). Problems that have been solved for years and used at massive scale.
I am assuming by "keep the session server side", you mean keep it in the RAM. If you want to keep the session in the ram, store it in memcache or redis.
Also, the more complex an app becomes, it's generally desirable to have less state, not more(as in sticky sessions).
I'm not sure I agree with either of your points. Sticky sessions with in app/JVM/whatever RAM session objects is much faster than pulling from memcache/redis and parsing/deserializing/instantiating the session state for each request.
Not at all sure what you mean by your second point. Sure generally simplifying things is desirable, but by complex app, I mean an app that has requirements that are complex, and many of those apps require additional session state. For instance keeping track of all categories and products browsed to target recommended products. Keep track of users' site browsing preference, search results, multi-tab interaction, etc...
Server based lookups have their own problems. An attacker can guess a session ID and spoof that customer. Storing hundreds of thousands of session IDs on disk or in the database can lead to performance problems. You'd leak huge amounts of information if someone were to gain access to the database or filesystem where these cookies are stored.
You can argue about solutions to each of these. My point is that each solution has their own problems. IMO, play's solution has worked well so far, making it easy to scale horizontally. I've been using play for 3 years. One security issue in 3 years, with a quick patch applied, is acceptable. Before that we used PHP, and we had many problems dealing with the huge volume of sessions to be handled.
Because signed session data is a great idea. Only slightly more data than an identifier traded for one less lookup and much higher flexibility server-side.
This implementation appears to have a bug in the signing mechanism, which is pretty bad. That's why we use existing crypto libraries.
That's how we implement flaws in the process, around crypto libraries. The price of session-cache lookups is the price paid not to worry there is a serious undiscovered security flaw waiting for you around the corner.
Its a price you have to decide if its worth paying.
You're basically saying that if everything works as expected, then a signed cookie is no different than an opaque handle to server-side data. But it doesn't answer (IMHO) the point that there are more things that can go wrong with a signed cookie. IMHO, YMMV.
Here are some challenges that occurred to me in a signed-cookie approach:
1) How is the signing key generated? If it's the output of a weak PRNG, maybe it can be bruteforced?
2) Where is it stored? Hard-coded in source? Data file? Command line param?
3) Same signing key on multiple servers?
4) Do you regenerate the keys periodically?
5) What if a team member leaves. Do signing keys get regenerated?
With a DB-based approach, your session data just piggybacks on the server security infrasturcture that you would have built anyway.
You're not wrong, but note that the usual random-handle-to-server-side-state still needs good random (1) that is not correlated across servers (equivalent of 3; don't spin up VMs with the same data in the random pool!) And if you have long-lived admin sessions, you may need to think about (5) too, especially if the company does not own all the hardware that employees use.
if the crypto library is Nacl or keyczar, then yes, maybe, but there are still a hundred ways to fuck up. If one is calling the aes function from openssh directly then no, I am bound to get it wrong.
And the whole argument about having magically independant servers that do not need to do any secure callbacks is totally blown away by the standard approach to CSRF protection - you send a nonce to the client. If it comes back to an "independant" server, the nonce still has to be looked up and confirmed. maybe you can use cycled hashes but at some point, we need to get a server make a security callback. It just has to happen to keep things simple.
The idea is so appealing to some because it means any host serving that web application can handle your request, rather than being forced to use "sticky sessions". Otherwise you have to move the session data into the database, which can be unappealing as well.
While I agree with you that putting session data in a cookie is a risky idea, I had a question:
> I have even written my own session handling wsgi middleware just because I don't understand encryption and cannot find a framework that doesn't try that.
You wrote your own library that stores in plaintext because you weren't sure that pre-existing libraries were doing crypto correctly?
Why couldn't you treat those other libs' ciphertext as plaintext and apply your custom security engineering to it.
Session id in a secured cookie and then loading the session from db/memcache/ram/custom-backend is standard practice and is something that is provided by most frameworks. What exactly did you gain by using a non-signed cookie other than opening yourself to replay attacks? If you felt like directly setting a cookie instead of just `session['user_id'] = some-user-id`, why did you forgo signed cookies?
2.1.x and forward has settled down a lot. They're still doing a lot of work under the hood to improve HTTP pipelining and other fun things. Worth reading their future roadmap.
Seems the Android guys are facing the same problems with Groovy in their Gradle based build system, and the Gradle team are considering switching to Scala for Gradle 2 to keep Android on board.
Note that a fix is available -- patched versions of Play are available all major releases. So it might mean a redeploy of code but it's not a big deal.
If the issue can be caused by inserting null bytes into the session, then it sounds like the signed cookie verification might have stopped at the first null byte, allowing the attacker to place other data after the null byte which the application would continue to read and use.
It looks like they used the null byte as a separator with the assumption that users couldn't submit a null byte. So attacker could submit a value like foo\x00user:admin and it would be serialised as user:bad\x00key:foo\x00user:admin and deserialized as key:foo, user:admin. that's my takeaway from the patch. I haven't played with it so I could be off track.
Its between hard and impossible to build to systems perfectly that do this, whereas a server based lookup has a limited number of attacks that do not involve owning my boxes.
I have even written my own session handling wsgi middleware just because I don't understand encryption and cannot find a framework that doesn't try that.