I'm going to play devil's advocate here, not out of any personal
malice, but simply because it's important to have *someone* do it in a
case like this. Now...
"Secure" is an awfully tricky word. What you're actually asking for is
to have the Django sessions module rewritten to suit your specific
security needs, which is very different from what you're saying.
Please be careful with the word "secure", because there's really no
such thing as a "secure" application[1], only an application which
suits the security needs of the use case it was designed for.
> Currently Django is vulnerable to session
> hijacking. Even though the length of the keys are long, a brute force
> attack would not be difficult to gain access to a site until they get
> a valid item in the page they're trying to access.
Brute-forcing a session is always going to be possible to a greater or
lesser extent. The question here, then, is not "how do we prevent
brute-forcing", but "how difficult do we want to make it" and, by
extension, "how complex do we want to make the default sessions
framework"; the perceived extra security of a different mechanism
would necessarily involve a trade-off of extra complexity in the
sessions framework, and it may not be possible to keep that extra
complexity from showing through in common use cases, so a careful
discussion of whether the gain from make that trade-off is worth the
downside is important to have.
> Giving the client
> two keys makes a site more secure to a point. Users who don't use a
> secure connection over SSL are still at risk since packets can be
> sniffed, however administrators are expected to force logged in users
> to use a secure connection.
If packet sniffing is a worry, SSL is the solution.
> 1) People have been using this exploit for years
> http://www.theregister.co.uk/2005/06/08/hotmail_hack/
People have been using social engineering for even longer; should we
forbid users of Django-based applications from reading email or
talking to strangers on the street (anybody remember the study which
found people would trade their passwords for a chocolate bar?)? ;)
> 2) This means anyone who runs Django and uses the default sessions
> module is running an insecure site by design.
See above about "security", and be very careful about generalizing
from a specific use case; "this does not meet my application's
security needs" does not necessarily equate to "this is insecure by
design".
> There is only 1 key to crack, if the site is a medical database, then
> the site would be a target. I do plan to be using Django in a medical
> environment, and am rather disgusted at the current state because the
> ticket was opened 11 months ago.
The code was implemented as a third-party application, freely
available to anyone who wants or needs to use it. Having proposed
additions to django.contrib -- which is what that patch was -- spend
time first as third-party applications in order to let them evolve and
ensure they're widely-used enough to be good contrib candidates is
generally how Django works.
> 3) Why is it taking so long to look at needed features and
> insecurities like this? My example patch took 8 months for someone to
> implement and commit to trunk.
Again, be careful about generalizing from specific use cases to Django
as a whole. "This is a high priority for my application" does *not*
necessarily translate to "this is a high priority for the Django
framework".
> My recommendation is to incorporate code in the default session module
> which is included in Django.
> http://code.google.com/p/django-signedcookies/
In general, recommendations which come without a confrontational
attitude tend to be more widely appreciated than recommendations which
do.
[1] Actually, a "secure" web application is possible. It just starts
with not ever connecting the application to the Web. Ideally, the
server on which the application code and database is kept will also be
stored inside a nuclear-hardened bunker, guarded 24/7 by military
special forces, and with constant surveillance provided by
intelligence agencies. For maximum security, the server should be
unplugged from electrical connections, have all input devices removed,
and be dismantled, run through magnetic scrambling and burned, with
the combustion by-products and burned remains then ejected into a
convenient singularity to insure the information is removed from this
universe. Security recommendations in this footnote assume you do not
care if entities in other universes are later able to retrieve
sensitive information.
--
"Bureaucrat Conrad, you are technically correct -- the best kind of correct."
1) the hotmail_hack story you point to is about cross-site scripting,
which has nothing to do with the security of cookies.
2) the signedcookies code you point to for inclusion in Django
explicitly discusses the idea that sessions are not vulnerable and
therefore their cookies don't need to be signed.
In any case, if the signedcookies code makes you feel better about the
security of your site, you should certainly use it. There's no point in
being "disgusted" at Django as a whole.
--Ned.
As that's my code, I think i'm qualified to discuss it a bit. First,
don't pretend I'm some sort of security expert who came in to save the
day for all insecure applications. I wrote that code after a brief
exchange with Simon WIllison when editing the Django Book last winter.
It was my first contribution to Django, as evidenced by the fact that
I started with a patch for a feature that really doesn't need to be
included in trunk at all.
That said, James is right. There's absolutely nothing stopping you
from using the signedcookies code as it stands right now, without
being part of Django proper. That is, after all, the entire point of
releasing it as its own app. I'm glad you think it's a good idea, and
I'd love to hear your experiences with it, so I can improve it based
on your feedback.
As for the actual security of signed cookies, they're still vulnerable
to at least two problems. For one, the signature method is still
susceptible to brute force methods, as you yourself admit that using
two keys only makes it "more secure to a point". To my knowledge,
there's nothing that can be done to completely prevent brute force
attacks like that.
The bigger problem, however, is that signed cookies are perfectly
valid, regardless of which machine they come from. Cookie theft is a
very real problem, and it's something that the signedcookies doesn't
handle at all. It might be possible to incorporate the user's IP in
the signature as well, but I fear that would lock out more people than
it should, if a user's IP changes during a session (yes, it can
happen), or it could be useless behind certain kinds of proxies.
So, to sum up, feel free to use signed cookies if you like, and let me
know what you think. Submit tickets if you have new features or
bugfixes. But don't expect it to be a silver bullet that will
magically secure your application. It certainly helps in most cases,
but it's not a cure-all. If you're as concerned with security as it
sounds like you are, you might look at SecurID.[1]
-Gul
Don't kid yourself. If the Hollywood writers weren't on strike, I bet
Matt Damon could still get in. ;)
-Gul
I'm not sure what makes you believe that two cookies are more secure
than one. Two n-bit strings are just as secure as one 2n-bit so a
simple answer would be: make the session ID twice as long.
Also, if you are securing an administration panel, write a custom
middleware or even better a view decorator that stores the IP in the
session and clears the session if the IP changes.
A trivial thing to do and you are free to only apply it to views where
it actually makes sense (so regular users can switch IPs as much as
they want while admins get logged out if their IP changes).
If you need strong security, use SSL combined with signed client
certificates to authenticate (again, even SSL certificates can be
bruteforced if you throw enough computing power at them).
--
Patryk Zawadzki
PLD Linux Distribution
Glad to hear it.
> The way I think of the second cookie, is more like a 2nd password.
> Sure, there is a possibility of a brute force with it to, but it is
> less likely they'll brute force a 2nd session id key along with the
> first.
Less likely, yes, but still possible. If you're really just concerned
with likelihood and probability, as opposed to pure security, I think
you'll find the track record of Django's session framework quite
suitable for most needs. And if you need to lower the probability of
exploitation even further, feel free to apply the signedcookies
middleware. It's easy.
> What would be interesting is to modify the session framework to "ban"
> an ip once it has made several Suspicious attempts. What is the point
> of raising a Suspicious exception if it does nothing?
But what's the point of banning an IP if you yourself admit that it's
not a reliable way to identify someone? Of course, writing something
like that would be quite easy to implement in a custom middleware. In
fact, you'd be able to have it catch any SuspciousOperation exceptions
for any request,[1] which would allow it to function on sessions,
signed cookies, or anything else that raises that exception.
Just have it cache a dictionary, mapping IPs to the number of
SuspiciousOperations, and automatically return HTTP 403 for any IP
with a number higher than whatever limit you like. It'd be fairly
straightforward, just make sure to store it in a proper cache, rather
than a module-level dictionary, since those are unique per-process,
and subsequent requests are likely to be served from different
processes.
-Gul
[1] http://www.djangoproject.com/documentation/middleware/#process-exception
And that's exactly what the signed cookies middleware would do, if you
applied it to the sessions framework.
-Gul
-Gul
[1] http://code.google.com/p/django-signedcookies/
> In any case, if the signedcookies code makes you feel better about
> the security of your site, you should certainly use it. There's no
> point in being "disgusted" at Django as a whole.
Agreed - to put it mildly! Django uses a 128 bit session key -- 32
hexadecimal characters. The computational power just to cycle through
these values is vast: Wikipedia: "one would need a device consuming at
a minimum 10 gigawatts (about the equivalent of eight large, dedicated
nuclear reactors) running continuously for 100 years."
But the time argument is even stronger -- since you are talking about a
session key for a web app, the *only* way to check if you have the
right key is to attempt to access a restricted page, which is going to
take a significant fraction of a second (say 0.10 sec for a typical
Django request). Do the sums, and you're gonna need 10^30 years to
brute force that. (Yep, that's a thousand billion billion billion
years).
Luke
--
"Making it up? Why should I want to make anything up? Life's bad enough
as it is without wanting to invent any more of it." (Marvin the
paranoid android)
Luke Plant || http://lukeplant.me.uk/