Skip to content

Commit 0f4fff7

Browse files
dennybiasiollijacobtylerwalls
authored andcommitted
Fixed #37078 -- Deprecated SHA-1 default for salted_hmac() and base64_hmac() algorithm.
Deprecated the default value of the algorithm argument in django.utils.crypto.salted_hmac() and django.core.signing.base64_hmac(), which will change from 'sha1' to 'sha256' in Django 7.0.
1 parent 920b43e commit 0f4fff7

6 files changed

Lines changed: 74 additions & 6 deletions

File tree

django/core/signing.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@
3838
import datetime
3939
import json
4040
import time
41+
import warnings
4142
import zlib
4243

4344
from django.conf import settings
4445
from django.utils.crypto import constant_time_compare, salted_hmac
46+
from django.utils.deprecation import RemovedInDjango70Warning, django_file_prefixes
4547
from django.utils.encoding import force_bytes
4648
from django.utils.module_loading import import_string
4749
from django.utils.regex_helper import _lazy_re_compile
@@ -96,7 +98,17 @@ def b64_decode(s):
9698
return base64.urlsafe_b64decode(s + pad)
9799

98100

99-
def base64_hmac(salt, value, key, algorithm="sha1"):
101+
# RemovedInDjango70Warning: algorithm="sha256"
102+
def base64_hmac(salt, value, key, algorithm=None):
103+
if algorithm is None:
104+
warnings.warn(
105+
"The default argument for algorithm in base64_hmac() will change "
106+
"from 'sha1' to 'sha256' in Django 7.0. Pass an explicit "
107+
"algorithm to silence this warning.",
108+
category=RemovedInDjango70Warning,
109+
skip_file_prefixes=django_file_prefixes(),
110+
)
111+
algorithm = "sha1"
100112
return b64_encode(
101113
salted_hmac(salt, value, key, algorithm=algorithm).digest()
102114
).decode()

django/utils/crypto.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
import hashlib
66
import hmac
77
import secrets
8+
import warnings
89

910
from django.conf import settings
11+
from django.utils.deprecation import RemovedInDjango70Warning, django_file_prefixes
1012
from django.utils.encoding import force_bytes
1113

1214

@@ -16,14 +18,27 @@ class InvalidAlgorithm(ValueError):
1618
pass
1719

1820

19-
def salted_hmac(key_salt, value, secret=None, *, algorithm="sha1"):
21+
# RemovedInDjango70Warning: algorithm="sha256"
22+
def salted_hmac(key_salt, value, secret=None, *, algorithm=None):
2023
"""
2124
Return the HMAC of 'value', using a key generated from key_salt and a
2225
secret (which defaults to settings.SECRET_KEY). Default algorithm is SHA1,
2326
but any algorithm name supported by hashlib can be passed.
2427
28+
Removed in Django70Warning: The default algorithm will change to SHA256
29+
in Django 7.0, so provide an explicit algorithm to silence the warning.
30+
2531
A different key_salt should be passed in for every application of HMAC.
2632
"""
33+
if algorithm is None:
34+
warnings.warn(
35+
"The default argument for algorithm in salted_hmac() will change "
36+
"from 'sha1' to 'sha256' in Django 7.0. Pass an explicit "
37+
"algorithm to silence this warning.",
38+
category=RemovedInDjango70Warning,
39+
skip_file_prefixes=django_file_prefixes(),
40+
)
41+
algorithm = "sha1"
2742
if secret is None:
2843
secret = settings.SECRET_KEY
2944

docs/internals/deprecation.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ details on these changes.
8080
* Support for double-dot variable lookup, like ``{{ book..title }}``,
8181
is removed.
8282

83+
* The default value of the ``algorithm`` argument for
84+
``django.utils.crypto.salted_hmac()`` and
85+
``django.core.signing.base64_hmac()`` will change from ``"sha1"`` to
86+
``"sha256"``.
87+
8388
.. _deprecation-removed-in-6.1:
8489

8590
6.1

docs/releases/6.1.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,12 @@ Miscellaneous
589589
deprecated. This syntax maps to a lookup of the empty string, which is
590590
normally a mistake.
591591

592+
* The default value of the ``algorithm`` argument for
593+
``django.utils.crypto.salted_hmac()`` and
594+
``django.core.signing.base64_hmac()`` is deprecated and will change from
595+
``"sha1"`` to ``"sha256"`` in Django 7.0. Pass an explicit ``algorithm``
596+
to silence the deprecation warning.
597+
592598
Features removed in 6.1
593599
=======================
594600

tests/signing/tests.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from django.test import SimpleTestCase, override_settings
55
from django.test.utils import freeze_time
66
from django.utils.crypto import InvalidAlgorithm
7+
from django.utils.deprecation import RemovedInDjango70Warning
78

89

910
class TestSigner(SimpleTestCase):
@@ -43,6 +44,15 @@ def test_signature_with_salt(self):
4344
signing.Signer(key="predictable-secret", salt="two").signature("hello"),
4445
)
4546

47+
def test_base64_hmac_default_algorithm_deprecation(self):
48+
msg = (
49+
"The default argument for algorithm in base64_hmac() will change "
50+
"from 'sha1' to 'sha256' in Django 7.0. Pass an explicit "
51+
"algorithm to silence this warning."
52+
)
53+
with self.assertWarnsMessage(RemovedInDjango70Warning, msg):
54+
signing.base64_hmac("salt", "value", "key")
55+
4656
def test_custom_algorithm(self):
4757
signer = signing.Signer(key="predictable-secret", algorithm="sha512")
4858
self.assertEqual(

tests/utils_tests/test_crypto.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
pbkdf2,
99
salted_hmac,
1010
)
11+
from django.utils.deprecation import RemovedInDjango70Warning
1112

1213

1314
class TestUtilsCryptoMisc(SimpleTestCase):
@@ -24,20 +25,30 @@ def test_constant_time_compare(self):
2425

2526
def test_salted_hmac(self):
2627
tests = [
27-
((b"salt", b"value"), {}, "b51a2e619c43b1ca4f91d15c57455521d71d61eb"),
28-
(("salt", "value"), {}, "b51a2e619c43b1ca4f91d15c57455521d71d61eb"),
28+
(
29+
(b"salt", b"value"),
30+
{"algorithm": "sha1"},
31+
"b51a2e619c43b1ca4f91d15c57455521d71d61eb",
32+
),
2933
(
3034
("salt", "value"),
31-
{"secret": "abcdefg"},
35+
{"algorithm": "sha1"},
36+
"b51a2e619c43b1ca4f91d15c57455521d71d61eb",
37+
),
38+
(
39+
("salt", "value"),
40+
{"secret": "abcdefg", "algorithm": "sha1"},
3241
"8bbee04ccddfa24772d1423a0ba43bd0c0e24b76",
3342
),
3443
(
3544
("salt", "value"),
36-
{"secret": "x" * hashlib.sha1().block_size},
45+
{"secret": "x" * hashlib.sha1().block_size, "algorithm": "sha1"},
3746
"bd3749347b412b1b0a9ea65220e55767ac8e96b0",
3847
),
3948
(
4049
("salt", "value"),
50+
# RemovedInDjango70Warning: Remove the explicit algorithm to
51+
# test the new default value.
4152
{"algorithm": "sha256"},
4253
"ee0bf789e4e009371a5372c90f73fcf17695a8439c9108b0480f14e347b3f9ec",
4354
),
@@ -56,6 +67,15 @@ def test_salted_hmac(self):
5667
with self.subTest(args=args, kwargs=kwargs):
5768
self.assertEqual(salted_hmac(*args, **kwargs).hexdigest(), digest)
5869

70+
def test_salted_hmac_default_algorithm_deprecation(self):
71+
msg = (
72+
"The default argument for algorithm in salted_hmac() will change "
73+
"from 'sha1' to 'sha256' in Django 7.0. Pass an explicit "
74+
"algorithm to silence this warning."
75+
)
76+
with self.assertWarnsMessage(RemovedInDjango70Warning, msg):
77+
salted_hmac("salt", "value")
78+
5979
def test_invalid_algorithm(self):
6080
msg = "'whatever' is not an algorithm accepted by the hashlib module."
6181
with self.assertRaisesMessage(InvalidAlgorithm, msg):

0 commit comments

Comments
 (0)