From 5bd390349ccb93f1189841ea0339bfc52794a0c4 Mon Sep 17 00:00:00 2001
From: David Wolever <david@wolever.net>
Date: Mon, 9 Jun 2014 18:15:21 -0400
Subject: [PATCH] Warn on unsafe value of 'sep=' in Signer
---
django/core/signing.py | 16 ++++++++++++++++
tests/signing/tests.py | 18 ++++++++++++++++++
2 files changed, 34 insertions(+)
diff --git a/django/core/signing.py b/django/core/signing.py
index d1f204b..8f31aa8 100644
a
|
b
|
from __future__ import unicode_literals
|
38 | 38 | import base64 |
39 | 39 | import json |
40 | 40 | import time |
| 41 | import warnings |
41 | 42 | import zlib |
42 | 43 | |
43 | 44 | from django.conf import settings |
44 | 45 | from django.utils import baseconv |
| 46 | from django.utils.deprecation import RemovedInNextVersionWarning |
45 | 47 | from django.utils.crypto import constant_time_compare, salted_hmac |
46 | 48 | from django.utils.encoding import force_bytes, force_str, force_text |
47 | 49 | from django.utils.module_loading import import_string |
48 | 50 | |
| 51 | _SEP_UNSAFE = set( |
| 52 | "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 53 | "abcdefghijklmnopqrstuvwxyz-_=" |
| 54 | ) |
49 | 55 | |
50 | 56 | class BadSignature(Exception): |
51 | 57 | """ |
… |
… |
class Signer(object):
|
150 | 156 | def __init__(self, key=None, sep=':', salt=None): |
151 | 157 | # Use of native strings in all versions of Python |
152 | 158 | self.sep = force_str(sep) |
| 159 | sep_is_invalid = sep != ":" and ( |
| 160 | not self.sep or |
| 161 | self.sep[0] in _SEP_UNSAFE or |
| 162 | self.sep[-1] in _SEP_UNSAFE |
| 163 | ) |
| 164 | if sep_is_invalid: |
| 165 | warnings.warn( |
| 166 | "Unsafe Signer separator: %r (cannot be in %r)" |
| 167 | % (self.sep, "".join(_SEP_UNSAFE)), |
| 168 | RemovedInNextVersionWarning) |
153 | 169 | self.key = key or settings.SECRET_KEY |
154 | 170 | self.salt = force_str(salt or |
155 | 171 | '%s.%s' % (self.__class__.__module__, self.__class__.__name__)) |
diff --git a/tests/signing/tests.py b/tests/signing/tests.py
index 740fc1c..cb803a1 100644
a
|
b
|
|
1 | 1 | from __future__ import unicode_literals |
2 | 2 | |
3 | 3 | import time |
| 4 | import warnings |
4 | 5 | |
5 | 6 | from django.core import signing |
6 | 7 | from django.test import TestCase |
… |
… |
class TestSigner(TestCase):
|
111 | 112 | s = signing.Signer(binary_key) |
112 | 113 | self.assertEqual('foo:6NB0fssLW5RQvZ3Y-MTerq2rX7w', s.sign('foo')) |
113 | 114 | |
| 115 | def _test_invalid_sep(self, sep): |
| 116 | with warnings.catch_warnings(record=True) as recorded: |
| 117 | warnings.simplefilter('always') |
| 118 | signing.Signer(sep=sep) |
| 119 | self.assertEqual(len(recorded), 1) |
| 120 | msg = str(recorded[0].message) |
| 121 | self.assertTrue(msg.startswith("Unsafe Signer separator")) |
| 122 | |
| 123 | def test_issues_warning_on_empty_invalid_sep(self): |
| 124 | self._test_invalid_sep("") |
| 125 | |
| 126 | def test_issues_warning_on_single_chr_invalid_sep(self): |
| 127 | self._test_invalid_sep("-") |
| 128 | |
| 129 | def test_issues_warning_on_multi_chr_invalid_sep(self): |
| 130 | self._test_invalid_sep("abc") |
| 131 | |
114 | 132 | |
115 | 133 | class TestTimestampSigner(TestCase): |
116 | 134 | |