Why using django.contrib.sessions as the salt to encode session data? why not secret key?

314 views
Skip to first unread message

Lokesh Sanapalli

unread,
Oct 3, 2022, 3:43:26 AM10/3/22
to Django developers (Contributions to Django itself)
Hi,

I was going through the code and got a question. I saw that we are using hard-coded string `django.contrib.sessions` as the key salt to encode session data. Why not using the secret key? as the secret key is specific to environment and project it serves as a good candidate. Is it because the session data does not contain any sensitive info (it only contains user id and other info) so that's why this decision is made?

Thanks & Regards,
Lokesh Sanpalli

Adam Johnson

unread,
Oct 5, 2022, 5:45:58 PM10/5/22
to django-d...@googlegroups.com

This actually changed from using the secret key as the salt, to the fixed string, whilst also changing the algorithm from MAC to HMAC. But I cannot see any discussion on why in the ticket: https://code.djangoproject.com/ticket/14445 .

🤷‍♂️

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/6c6544b7-a190-4198-9108-6c66fac213ebn%40googlegroups.com.

John Whitlock

unread,
Oct 5, 2022, 10:44:09 PM10/5/22
to django-d...@googlegroups.com
Looking at the code, the hard-coded salt seems OK to me. The encoding is done by SessionBase.encode(), which calls dumps() from django.core.signing. The docstring says:

Return URL-safe, hmac signed base64 compressed JSON string. If key is None, use settings.SECRET_KEY instead. The hmac algorithm is the default Signer algorithm.

If compress is True (not the default), check if compressing using zlib can save some space. Prepend a '.' to signify compression. This is included in the signature, to protect against zip bombs.

Salt can be used to namespace the hash, so that a signed string is only valid for a given namespace. Leaving this at the default value or re-using a salt value across different parts of your application without good cause is a security risk.

The serializer is expected to return a bytestring.

So, settings.SECRET_KEY is used to sign the session, and salt acts like a namespace to distinguish sessions from other uses of the SECRET_KEY.

Trying it out in `./manage.py shell`:

>>> from django.contrib.sessions.backends.db import SessionStore
>>> from django.core.signing import b64_decode
>>> session = SessionStore().encode({"foo": "bar"})
>>> print(session)
eyJmb28iOiJiYXIifQ:1ogD1v:OIpRWKZdxbhox3d7XaS7A0bZouEXQV6jx03FlAaDGZo
>>> val, ts, sign = session.split(':')
SessionStore().encode({"foo": "bar"})
>>> b64_decode(val.encode())
b'{"foo":"bar"}'
>>> b64_decode(ts.encode())
b'\xd6\x88\x03\xd6'
>>> b64_decode(sign.encode())
b'8\x8aQX\xa6]\xc5\xb8h\xc7w{]\xa4\xbb\x03F\xd9\xa2\xe1\x17A^\xa3\xc7M\xc5\x94\x06\x83\x19\x9a'
>>> len(b64_decode(z.encode()))
32

The first section of the session value is the encoded value, base64 encoded, and potentially compressed.
The second section is the encoded timestamp, used to determine if it was created too long ago on decode
The third section is the HMAC signature, base64 encoded.

- John

Avantika gohane

unread,
Oct 7, 2022, 3:42:55 PM10/7/22
to django-d...@googlegroups.com
hey....avantika this side 

Adam Johnson

unread,
Oct 12, 2022, 6:25:00 PM10/12/22
to django-d...@googlegroups.com
Thank you for diving into this John! All seems sensible then.

James Bennett

unread,
Oct 12, 2022, 8:03:49 PM10/12/22
to django-d...@googlegroups.com
On Wed, Oct 12, 2022 at 3:25 PM 'Adam Johnson' via Django developers (Contributions to Django itself) <django-d...@googlegroups.com> wrote:
Thank you for diving into this John! All seems sensible then.
Yeah, the threat model here is you have, say, Endpoints A and B that each work with HMAC'd values, and Endpoint A generates them based at least in part on user input. With some cleverness, an attacker might figure out how to get Endpoint A to generate an HMAC that Endpoint B will accept as valid.

Now, imagine that Endpoint B is, say, password reset.

This is why uses of HMAC should be namespaced. It's maybe unfortunate that the exact keyword argument is named "salt" when people are used to that being a unique-per-call random value rather than a constant, but a constant is the expected pattern for many usages of HMAC in Django and in Django apps.
Reply all
Reply to author
Forward
0 new messages