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.
This commit is contained in:
MattBlack85 2014-02-16 14:47:51 +01:00 committed by Honza Král
parent 8274fa60f8
commit a8ba76c2d3
4 changed files with 31 additions and 5 deletions

View File

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

View File

@ -36,10 +36,13 @@ def salted_hmac(key_salt, value, secret=None):
if secret is None: if secret is None:
secret = settings.SECRET_KEY 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 # 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 # passing the key_salt and our base key through a pseudo-random function and
# SHA1 works nicely. # 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 # If len(key_salt + secret) > sha_constructor().block_size, the above
# line is redundant and could be replaced by key = key_salt + secret, since # line is redundant and could be replaced by key = key_salt + secret, since

View File

@ -2,6 +2,7 @@ from __future__ import unicode_literals
import time import time
from django.conf import settings
from django.core import signing from django.core import signing
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.test import TestCase from django.test import TestCase
@ -62,3 +63,18 @@ class SignedCookieTest(TestCase):
request.get_signed_cookie, 'c', max_age=10) request.get_signed_cookie, 'c', max_age=10)
finally: finally:
time.time = _time 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')

View File

@ -105,6 +105,12 @@ class TestSigner(TestCase):
self.assertRaises( self.assertRaises(
signing.BadSignature, signing.loads, transform(encoded)) 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): class TestTimestampSigner(TestCase):