30

I am nearing a point where I will deploy my Django application to the hostile environment otherwise known as "the internet" and I'm trying to better understand the ramifications of the Django SECRET_KEY. One of the standard procedures it seems is to secure the secret key in the settings.py. Fair enough. The docs go so far to say to not commit your secret key to SVN, CVS, etc... For this provides easy access to your key. However, if anyone were tempted to commit the secret key to their repo, this would indicate that the secret key is static (see question #4)?

Anyway, here are my questions:

  1. How is storing the secret key as an environment variable any more secure than storing it directly in settings.py? For example, if an attacker can read settings.py, he more than likely can just type $ echo $DJANGO_SECRET_KEY!
  2. How is storing the secret key in a file any more secure than storing it directly in settings.py? If he can read settings.py, he probably can read django_secret_key.txt.
  3. If the attacker has compromised your machine, can't they simply load the python interpreter with settings.py to > print settings.SECRET_KEY?
  4. Finally, would it be a bad practice to randomly generate the secret key each time the webserver process is restarted? This could be completely random, or it could prompt for user input for the key. Obviously, the latter presents a serious weakness if the attacker himself can restart the webservice and input the key of his choice.
James
  • 545
  • 2
  • 5
  • 8
  • 6
    I believe that this recommendation is for convenience and source security, and has little to do with stopping an attacker who has already gained access to a system. – David Houde Jun 26 '14 at 07:04

1 Answers1

22

Once an attacker already has access to the system it's already way too late. The main concern for not leaking the key is because it is often used as a seed for hashing and signing sessions. The idea is that your production SECRET_KEY needs to be completely different than your development or staging SECRET_KEY. You can actually randomly generate it every restart although this might impact user experience (see details below).

As long as you adhere to the principle of changing the key there is not much danger if you commit or not (as long as you ensure it is changed once going from dev to prod). If you don't, then someone having the key can predict the outcome of hashing algorithms (used for sessions) or even sign sessions.

If an attacker has gained access to your system you're already too far gone because it's not your system anymore. One thing you do need to ensure is that the file permissions on your settings file is only readable by the user running the webserver and by no-one else. This prevents someone who illegitemately gained access to a limited account, which is not the same as the webserver account, from compromising your key.

There is a good answer here on Stack Overflow: Django SECRET_KEY written by sberder which details what it is used for:

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.
Lucas Kauffman
  • 54,169
  • 17
  • 112
  • 196