A couple of years ago I posted on this topic to say that using ENV 
variables is dangerously subject to human error.  If it ever happens that 
(1) you put a server on the public internet with DEBUG on, and (2) a 
visitor can provoke a 5xx server error response, then all of your secrets 
will be dumped in the stack-trace output.

(Yes, I know people will say "don't do that" regarding point #1, and 
similarly say "never publish code with a possible 500 error event".  But if 
it ever happens, you are screwed.  And you won't necessarily know that it 
happened.)

In general, if your secrets are kept in plaintext in your github repository 
and your repository gets compromised, then you have lost everything.

I've tried to think of a way to store the secrets in a plaintext file and 
encrypt the file's contents before committing the ciphertext file to the 
repository.  The question, as always, is where to store they key for 
decrypting the secrets file.

I have an idea in which the encryption key is manufactured on the fly from 
some non-obvious fact about the repository contents.  I'd like to get 
feedback from the Django community about it.

Summary:

   - Put all secret info in a text file, but encrypt the file before it 
   gets committed into the repository.
   
   - *Use an encryption key that is derived from some fact about the files 
   in the repository.*
   
   - At runtime, use that same fact to derive the decryption key for the 
   secrets file.
   
   - Ensure that the runtime server can never reveal the fact that is the 
   basis of the encryption key.


Suppose for example that the encryption key is the SHA-1 hash value of 
urls.py.  This is calculated during the release process, and used to 
encrypt the plaintext secrets file.  Then the encrypted secrets file is 
committed to the repository, and ultimately gets deployed to production.

urls.py obviously changes over time.  But it is constant for any given 
commit of the entire codebase, which is what gets deployed. 

At start-up time, the Django server can open urls.py and hash the contents, 
and use that hash value to decrypt the contents of the secrets file.  As a 
result, the secrets are available at runtime, but they are never stored in 
a plaintext file.

Why is this secure?  It relies on two assumptions.

   1. Ensure that the contents of urls.py will never be published as part 
   of an HTTPResponse.
   
   When this is true, the runtime server cannot reveal the decryption key 
   for the encrypted secrets file.  That is to say, do not write a management 
   command with name "getthesecretdecryptionkey".
   
   2. Using security-through-obscurity, do not always use the same file 
   (urls.py) as the basis of the hash value.  Instead, use some obscure 
   selection criteria like "the seventh-largest .PY source file in the tree; 
   in case of a tie, use the alphabetically last file".
   
   Similarly, do not always use the same hash method; instead, select a 
   hash method from a list like [ "SHA-1, SHA-256, "MD5", ] by taking the size 
   of urls.py modulo the length of that list.

I look forward to hearing comments about this approach.

Bill Torcaso

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/91ae856c-8408-44c6-893d-12e1189a418d%40googlegroups.com.

Reply via email to