Fix issue that occurs when using bytes as secret key. - #890
Conversation
Current coverage is 76.72% (diff: 100%)@@ master #890 diff @@
==========================================
Files 30 30
Lines 1653 1654 +1
Methods 0 0
Messages 0 0
Branches 245 245
==========================================
+ Hits 1268 1269 +1
Misses 311 311
Partials 74 74
|
|
I don't think that The default, empty value is https://docs.djangoproject.com/en/1.10/ref/settings/#std:setting-SECRET_KEY doesn't say anything about If you look at the implementation of In a 12-factor app it's a best practice to provide secrets via environment variables and random bytes (half of which are non-ASCII) aren't safe to pass via environment variables. That said, it's best not to crash when SECRET_KEY contains I don't see the point of randomizing the SECRET_KEY in the tests setting, what problem is this solving? |
|
There is no default value for SECRET_KEY. If it's left out, Django will throw an error stating the SECRET_KEY is not set. Most of the code that requires the SECRET_KEY use it in methods that only accept it as bytes. For example, see django.utils.crypto (https://github.com/django/django/blob/master/django/utils/crypto.py). Setting the secret key shouldn't be limited to setting them via environment variables. In any case, the script has to fetch the SECRET_KEY from somewhere before placing it in an environment variable. As for why I changed the SECRET_KEY in the tests, I found that changing the key was the best way to verify make_hash still works. Leaving out the changes to make_hash and setting the SECRET_KEY to a non-UTF-8 byte string would cause the tests to fail. Placing the changes to make_hash and SECRET_KEY causes all tests to pass without modification. |
|
Was there any concern still about this change? |
|
I don't see any explanation for the removal of the newline normalization. Maybe there's a good reason for that and I don't see it? Please explain. Moving from force_text to force_bytes is certainly the right thing to do since hashlib expects bytes, and I agree that the crash should be fixed, even though I've never seen a SECRET_KEY consisting of bytes in the wild until now. |
|
I must ask, why was the input to the hash being modified in the first place? Note that replacing newlines with spaces gives you different hashes. For example... In [1]: import hashlib In [2]: hashlib.sha1(b'some long string').hexdigest() In [3]: hashlib.sha1(b'some\nlong\nstring').hexdigest() |
The Django secret key can and should be random bytes which may or may not be decodable to UTF-8.
|
The idea probably was that the SQL query would pass through a textarea or something where newlines might be changed from I've been thinking a bit, and modifying queries in the browser does not and should not work anyway. So I'm good with this change. |
|
Can we just remove the randomization of the secret key in tests? I really dislike randomness in tests, no matter the reason (except, of course, when testing a statistical process or something that explicitly deals with randomness). I thought I said that earlier but I can't find that comment 😕 |
|
The new secret key is not random at all. It's a byte string of bytes with values 0 through 255 in sorted order. |
|
Here is what that secret key is now. |
|
Ah, right, I had missed that change in your patch. However, like I explained at length earlier, putting bytes in the SECRET_KEY still goes against Django's expectations and established practice. There's even a ticket about it: https://code.djangoproject.com/ticket/24994. The changes to the test settings in this PR are not only useless but also wrong. |
|
|
||
| # Quick-start development settings - unsuitable for production | ||
|
|
||
| SECRET_KEY = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' |
There was a problem hiding this comment.
Please check the ticket you linked again (https://code.djangoproject.com/ticket/24994). They've closed the ticket without making any changes, referencing a comment I left to them (see django/django#7510).
Also note, the Django docs already recommended the use of external files for storing the SECRET_KEY, in which case it's reasonable to expect the SECRET_KEY be bytes, given the multiple ways files can be opened in Python (as bytes). See https://docs.djangoproject.com/en/stable/howto/deployment/checklist/#secret-key .
There was a problem hiding this comment.
open defaults to reading in text mode, which means that the snippet from the documentation returns text, not binary, which negates your point.
I can see the case for putting bytes in SECRET_KEY, especially now that the system check PR in Django has been closed. OTOH as Aymeric said it's not established practice, so please try submitting a documentation patch to Django saying bytes as SECRET_KEY is supported, and maybe even recommended. I don't see why DDT has to move first (especially since, with the rest of your changes, your use case will work perfectly).
Thanks!
|
I went ahead and merged your change with an added commit that reverts the Thanks for your contribution! |
The Django secret key can and should be random bytes which may or may
not be decodable to UTF-8.