Sun, 16 Aug 2009

More Django Paranoia

As Ryan pointed out in response to my previous post on django-paranoid-sessions, the only way to truly prevent sniffing or man-in-the-middle attacks is to operate over a secure connection. Fair enough, but HTTPS ain't free. The general consensus seems to be that a secure connection is too much overhead for anything but the high-value or high-risk sections of your website (login submissions, payment processing, nuclear launch codes, etc).

Ideally, it should be possible to place selected sections of your website behind a secure connection and gain added attack-resistance for those sections, while still sharing session data with the rest of the site. Using a recommendation from the OWASP session management guide, the latest release of django-paranoid-sessions now lets you do exactly that.

The idea is to maintain a second randomly-generated session key that is only sent when the client connects over a secure channel. Unencrypted requests within your session are oblivious to the second key, but if a secure request doesn't provide both valid session keys then it is rejected. You can think of this extra key as a second "security enhanced" session that transparently piggybacks on top of the standard session data.

Suppose an attacker is able to sniff your unencrypted requests, obtain your primary session key, and overcome any fingerprinting or nonce-related roadblocks. They are then able to impersonate you in any unencrypted request to the server. But since the second session key is only ever sent on a secure channel, it cannot be sniffed and the attacker cannot obtain enough information to impersonate you in a secure request. By enforcing that high-value or high-risk actions on your site can only be performed over a secure connection, you get resistance to sniffing or man-in-the-middle attacks without the overhead of serving the whole site over HTTPS.

As another little bonus, the latest version of django-paranoid-sessions also marks its session cookies as being httponly to help prevent them being stolen through cross-site scripting attacks. Unfortunately this is only available when running on Python 2.6 or later, since it must be supported by the underlying cookie-handling library.

Unlike the other security measures employed by this app, I haven't included a setting to disable secure-channel keys or http-only cookies; they're basically cost-free and provide a very real security benefit. Assuming anyone is actually using this yet, you should definitely grab the latest version asap.