Procházet zdrojové kódy

Fixed #19980: Signer broken for binary keys (with non-ASCII chars).

With this pull request, request #878 should considered closed.

Thanks to nvie for the patch.
MattBlack85 před 11 roky
rodič
revize
a8ba76c2d3

+ 5 - 4
django/core/signing.py

@@ -76,7 +76,8 @@ def base64_hmac(salt, value, key):
 
 def get_cookie_signer(salt='django.core.signing.get_cookie_signer'):
     Signer = import_string(settings.SIGNING_BACKEND)
-    return Signer('django.http.cookies' + settings.SECRET_KEY, salt=salt)
+    key = force_bytes(settings.SECRET_KEY)
+    return Signer(b'django.http.cookies' + key, salt=salt)
 
 
 class JSONSerializer(object):
@@ -148,9 +149,9 @@ class Signer(object):
 
     def __init__(self, key=None, sep=':', salt=None):
         # Use of native strings in all versions of Python
-        self.sep = str(sep)
-        self.key = str(key or settings.SECRET_KEY)
-        self.salt = str(salt or
+        self.sep = force_str(sep)
+        self.key = key or settings.SECRET_KEY
+        self.salt = force_str(salt or
             '%s.%s' % (self.__class__.__module__, self.__class__.__name__))
 
     def signature(self, value):

+ 4 - 1
django/utils/crypto.py

@@ -36,10 +36,13 @@ def salted_hmac(key_salt, value, secret=None):
     if secret is None:
         secret = settings.SECRET_KEY
 
+    key_salt = force_bytes(key_salt)
+    secret = force_bytes(secret)
+
     # We need to generate a derived key from our base key.  We can do this by
     # passing the key_salt and our base key through a pseudo-random function and
     # SHA1 works nicely.
-    key = hashlib.sha1((key_salt + secret).encode('utf-8')).digest()
+    key = hashlib.sha1(key_salt + secret).digest()
 
     # If len(key_salt + secret) > sha_constructor().block_size, the above
     # line is redundant and could be replaced by key = key_salt + secret, since

+ 16 - 0
tests/signed_cookies_tests/tests.py

@@ -2,6 +2,7 @@ from __future__ import unicode_literals
 
 import time
 
+from django.conf import settings
 from django.core import signing
 from django.http import HttpRequest, HttpResponse
 from django.test import TestCase
@@ -62,3 +63,18 @@ class SignedCookieTest(TestCase):
                 request.get_signed_cookie, 'c', max_age=10)
         finally:
             time.time = _time
+
+    def test_signed_cookies_with_binary_key(self):
+        def restore_secret_key(prev):
+            settings.SECRET_KEY = prev
+
+        self.addCleanup(restore_secret_key, settings.SECRET_KEY)
+
+        settings.SECRET_KEY = b'\xe7'
+
+        response = HttpResponse()
+        response.set_signed_cookie('c', 'hello')
+
+        request = HttpRequest()
+        request.COOKIES['c'] = response.cookies['c'].value
+        self.assertEqual(request.get_signed_cookie('c'), 'hello')

+ 6 - 0
tests/signing/tests.py

@@ -105,6 +105,12 @@ class TestSigner(TestCase):
             self.assertRaises(
                 signing.BadSignature, signing.loads, transform(encoded))
 
+    def test_works_with_non_ascii_keys(self):
+        binary_key = b'\xe7'  # Set some binary (non-ASCII key)
+
+        s = signing.Signer(binary_key)
+        self.assertEquals('foo:6NB0fssLW5RQvZ3Y-MTerq2rX7w', s.sign('foo'))
+
 
 class TestTimestampSigner(TestCase):