Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Effects of changing Django's SECRET_KEY

Tags:

django

People also ask

What is the most secure way to handle Django's Secret_key value?

protect against message tampering as the message framework may use cookies to pass messages between views. protect session data and create random session keys to avoid tampering as well. create random salt for most password hashers. create random passwords if necessary.

Which function is Django's Secret_key not used for?

It's not used for passwords.

Is Django secret key important?

Summary: The Django secret key is used to provide cryptographic signing. This key is mostly used to sign session cookies. If one were to have this key, they would be able to modify the cookies sent by the application.


Edit: This answer is based on django 1.5

SECRET_KEY is used in a lot of various places, I'll point out what is impacted by it first and then try to go over that list and give precise explanation of the impact.

The list of things using SECRET_KEY directly or indirectly:

  • JSON object signing
  • crypto functions for salted hmacs or seeding the random engine which impacts:
    • password reset token
    • comment form security to protect against forged POST requests
    • form security
    • protect against message tampering as the message framework may use cookies to pass messages between views.
    • protect session data and create random session keys to avoid tampering as well.
    • create random salt for most password hashers
    • create random passwords if necessary
    • create itself when using startproject
    • create CSRF key

In reality a lot of the items listed here use SECRET_KEY through django.utils.crypt.get_random_string() which uses it to seed the random engine. This won't be impacted by a change in value of SECRET_KEY.

User experience directly impacted by a change of value are:

  • sessions, the data decode will break, that is valid for any session backend (cookies, database, file based or cache).
  • password reset token already sent won't work, users will have to ask a new one.
  • comments form (if using django.contrib.comments) will not validate if it was requested before the value change and submitted after the value change. I think this is very minor but might be confusing for the user.
  • messages (from django.contrib.messages) won't validate server-side in the same timing conditions as for comments form.

UPDATE: now working on django 1.9.5, a quick look at the source gives me pretty much the same answers. Might do a thorough inspection later.


Since this question was asked, the Django documentation has changed to include an answer.

The secret key is used for:

  • All sessions if you are using any other session backend than django.contrib.sessions.backends.cache, or are using the default get_session_auth_hash().
  • All messages if you are using CookieStorage or FallbackStorage.
  • All PasswordResetView tokens.
  • Any usage of cryptographic signing, unless a different key is provided.

If you rotate your secret key, all of the above will be invalidated. Secret keys are not used for passwords of users and key rotation will not affect them.

It wasn't clear to me exactly how I should rotate the secret key. I found a discussion of how Django generates a key for a new project, as well as a Gist that discusses other options. I finally decided to just get Django to create a new project, copy the new secret key into my old project, and then erase the new project.

cd ~/junk # Go to some safe directory to create a new project.
django-admin startproject django_scratch
grep SECRET_KEY django_scratch/django_scratch/settings.py # copy to old project
rm -R django_scratch

Update

It looks like Django added the get_random_secret_key() function in version 1.10. You could use that to generate a new secret key.

$ ./manage.py shell -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
s!)5@5s79sp=92a+!f4v!1g0d0+64ln3d$xm1f_7=749ht&-zi
$ ./manage.py shell -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
_)+%kymd=f^8o_fea1*yro7atz3w+5(t2/lm2cz70*e$2mn\g3
$

According to this page https://docs.djangoproject.com/en/dev/topics/signing/, the SECRET_KEY is mostly used for transitory stuff -- signing data sent over the wire so you can detect tampering, for example. It looks like the things that COULD break are:

  • Signed cookies, e.g. "remember my auth on this computer" type values. In this case, the cookie will be invalidated, the signature will fail to verify and the user will have to re-authenticate.
  • For any users that have requested links for a password reset or a custom file download, those links will no longer be valid. The users would simply have to re-request those links.

Someone with more recent and/or salient Django experience than me might chime in otherwise, but I suspect that unless you are explicitly doing something with the signing API, this should only create a mild inconvenience for your users.


The SECRET_KEY string is primarily used for encrypting and/or hashing cookies data. A lot of frameworks (including Django) come to this since default session cookies have its own drawbacks.

Imagine that you have form in django for editing articles with a hidden field. In this hidden field is stored ID of article you have editing. And if you want to be sure that no-one can send you any other article id, you will add an extra hidden field with hashed id. So if someone will change the ID, you will know it because the hash won't be the same.

Of course this is a trivial example but this is how the SECRET_KEY is used.

Django is internaly using it for example for {% csrf_token %} and few more things. It really shouldn't have any impact on your application if you will change it, based on your question and that you aren't using it.

The only thing is that maybe the session values will be dropped. So for example users will have to login into admin again, because django won't be able to decode session with different key.


I made this same mistake. The default password was 50 long so I used powershell to generate a 50 long random string and replaced the old SECRET_KEY with it. I was logged in and after replacing the SECRET_KEY my previous session had been invalidated.

With Powershell (source):

# Load the .net System.Web namespace which has the GeneratePassword function
[Reflection.Assembly]::LoadWithPartialName("System.Web")

#  GeneratePassword(int length, int numberOfNonAlphanumericCharacters)
[System.Web.Security.Membership]::GeneratePassword(50,5)

With Bash (source):

# tr includes ABCabc123 and the characters from OWASP's "Password special characters list"
cat /dev/urandom | tr -dc 'A-Za-z0-9!"#$%&\''()*+,-./:;<=>?@[\]^_`{|}~' | head -c 100 ; echo

At this point I thought why not try a larger key, so I tried it with a 100 and 1000 long key. Both worked. If I understand the source code, the object returned by the signer function is a hmac hash in base64. RFC 2104 has this to say for the required length of a HMAC secret key.

Applications that use keys longer than B bytes will first hash the key using H and then use the resultant L byte string as the actual key to HMAC.

The key for HMAC can be of any length (keys longer than B bytes are first hashed using H). However, less than L bytes is strongly discouraged as it would decrease the security strength of the function. Keys longer than L bytes are acceptable but the extra length would not significantly increase the function strength. (A longer key may be advisable if the randomness of the key is considered weak.)

To translate into normal speak, the size of the secret key needs to be the same size as the output. The key also needs to be in bits. Each digit in base64 represents 6 bits. So if you had a 50 character password, you would have a 50 x 6 = 300 bit secret key. If you are using SHA256, then you would need a 256 bit key (sha256 uses 256 bits by definition). So a 50 long password should work unless you plan to use a hashing algorithm larger than SHA256.

But since any extra bits in the key are being hashed, the size of it wont drastically decrease performance. But it would guarantee you that you have a enough bits for larger hash functions. SHA-512 would be covered by a 100 long SECRET_KEY (50 x 6 = 600 bits > 512 bits).