Opened 4 months ago

Last modified 2 days ago

#36546 assigned Cleanup/optimization

Deprecate django.utils.crypto.constant_time_compare()

Reported by: Tim Graham Owned by: Pravin
Component: Utilities Version: dev
Severity: Normal Keywords:
Cc: JaeHyuckSa, Pravin Triage Stage: Someday/Maybe
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Historically it was a bespoke implementation (added in 45c7f427ce830dd1b2f636fb9c244fda9201cadb) before the stdlib implementation was preferred (58176dee88ac7c1038c7f685af023e634b143d02). Now it's just alias of secrets.compare_digest (which itself is an alias of hmac.compare_digest, which was used before 1d0bab0bfd77edcf1228d45bf654457a8ff1890d).

constant_time_compare() does call force_bytes() on its arguments but this was a workaround for Python 2.7 (7e3cf3cfd27e53ced0a1fc65a02849f78a292d3d) and no tests in Django's test suite fail with those calls removed.

Change History (23)

comment:1 by suhail vs, 4 months ago

what about adding a warning in function constant_time_compare in file django.utils.crypto.py

import warnings
from django.utils.deprecation import RemovedInNextVersionWarning

def constant_time_compare(val1, val2):
    """Return True if the two strings are equal, False otherwise."""
    warnings.warn(
        "constant_time_compare(val1, val2) is deprecated and will be removed in Django 6.0. "
        "`import secrets` from python standard library, then run secrets.compare_digest(val1,val2) instead.",
        RemovedInNextVersionWarning,
        stacklevel=2
    )
    return secrets.compare_digest(force_bytes(val1), force_bytes(val2))

`

comment:2 by Sarah Boyce, 4 months ago

Triage Stage: UnreviewedAccepted

comment:3 by JaeHyuckSa, 4 months ago

Owner: set to JaeHyuckSa
Status: newassigned

comment:4 by JaeHyuckSa, 4 months ago

Has patch: set

comment:5 by JaeHyuckSa, 4 months ago

Patch needs improvement: set

comment:6 by JaeHyuckSa, 4 months ago

Patch needs improvement: unset

comment:7 by Sarah Boyce, 3 months ago

Patch needs improvement: set

comment:8 by JaeHyuckSa, 3 months ago

Patch needs improvement: unset

comment:9 by Sarah Boyce, 3 months ago

Triage Stage: AcceptedReady for checkin

comment:10 by Sarah Boyce <42296566+sarahboyce@…>, 3 months ago

Resolution: fixed
Status: assignedclosed

In 0246f47:

Fixed #36546 -- Deprecated django.utils.crypto.constant_time_compare() in favor of hmac.compare_digest().

Signed-off-by: SaJH <wogur981208@…>

comment:11 by Sarah Boyce <42296566+sarahboyce@…>, 3 months ago

In d0e4dd5c:

Fixed #36572 -- Revert "Fixed #36546 -- Deprecated django.utils.crypto.constant_time_compare() in favor of hmac.compare_digest()."

This reverts commit 0246f478882c26bc1fe293224653074cd46a90d0.

comment:12 by Sarah Boyce, 3 months ago

Has patch: unset
Resolution: fixed
Status: closednew
Triage Stage: Ready for checkinSomeday/Maybe

Reopening following revert. See discussion in #36572

A later first step could be to replace internal usage of constant_time_compare() with compare_digest()

The deprecation itself needs more consideration

comment:13 by JaeHyuckSa, 3 months ago

There are quite a few points that need further discussion, so it’s difficult to move this forward right now. I’ll unassign myself for the time being

comment:14 by JaeHyuckSa, 3 months ago

Owner: JaeHyuckSa removed
Status: newassigned

comment:15 by JaeHyuckSa, 3 months ago

Cc: JaeHyuckSa added

comment:16 by Pravin, 8 days ago

What is current state, Can i work on this ?

comment:17 by Simon Charette, 7 days ago

Pravin, refer to the discussion on the revert commit in comment:12. Looks like we first want to stop using it internally.

comment:18 by Pravin, 3 days ago

Cc: Pravin added

comment:19 by Pravin, 3 days ago

@Simon Thanks for the more context.

I'm going to start working on this , First I will remove internal dependency on constant_time_compare.

comment:20 by Pravin, 3 days ago

Owner: set to Pravin

comment:21 by Pravin, 3 days ago

just confirming the technical approach for the internal dependency removal:

  1. I will be using secrets.compare_digest() for the replacement.
  2. The implementation at the call site will include force_bytes() on both arguments to ensure type safety: secrets.compare_digest(force_bytes(val1), force_bytes(val2)).
  3. The definition of constant_time_compare() itself will not be modified to avoid breaking third-party applications that rely on its current type-coercion logic.

Example of the change:

Old internal Django code:constant_time_compare(val1, val2)
New internal Django code: secrets.compare_digest(force_bytes(val1), force_bytes(val2))

I am proceeding with the internal refactoring now.

comment:22 by Tim Graham, 2 days ago

No, the force_bytes() is not needed in Django's use of constant_time_compare(), see ticket:36572#comment:4. The problem is only with third-party users of the function.

comment:23 by Pravin, 2 days ago

Hi Tim,
I was in that dilema and I was not so confident in removing force_bytes. But Since you confirmed it I can safely proceed ( i will no use force_bytes ). Thanks.

Note: See TracTickets for help on using tickets.
Back to Top