diff --git a/starlette/_compat.py b/starlette/_compat.py new file mode 100644 index 000000000..82aa72f38 --- /dev/null +++ b/starlette/_compat.py @@ -0,0 +1,26 @@ +import hashlib + +# Compat wrapper to always include the `usedforsecurity=...` parameter, +# which is only added from Python 3.9 onwards. +# We use this flag to indicate that we use `md5` hashes only for non-security +# cases (our ETag checksums). +# If we don't indicate that we're using MD5 for non-security related reasons, +# then attempting to use this function will raise an error when used +# environments which enable a strict "FIPs mode". +# +# See issue: https://github.com/encode/starlette/issues/1365 +try: + + hashlib.md5(b"data", usedforsecurity=True) # type: ignore[call-arg] + + def md5_hexdigest( + data: bytes, *, usedforsecurity: bool = True + ) -> str: # pragma: no cover + return hashlib.md5( # type: ignore[call-arg] + data, usedforsecurity=usedforsecurity + ).hexdigest() + +except TypeError: # pragma: no cover + + def md5_hexdigest(data: bytes, *, usedforsecurity: bool = True) -> str: + return hashlib.md5(data).hexdigest() diff --git a/starlette/responses.py b/starlette/responses.py index 1f9c43a21..ffde4b97d 100644 --- a/starlette/responses.py +++ b/starlette/responses.py @@ -1,4 +1,3 @@ -import hashlib import http.cookies import json import os @@ -12,6 +11,7 @@ import anyio +from starlette._compat import md5_hexdigest from starlette.background import BackgroundTask from starlette.concurrency import iterate_in_threadpool from starlette.datastructures import URL, MutableHeaders @@ -287,7 +287,7 @@ def set_stat_headers(self, stat_result: os.stat_result) -> None: content_length = str(stat_result.st_size) last_modified = formatdate(stat_result.st_mtime, usegmt=True) etag_base = str(stat_result.st_mtime) + "-" + str(stat_result.st_size) - etag = hashlib.md5(etag_base.encode()).hexdigest() + etag = md5_hexdigest(etag_base.encode(), usedforsecurity=False) self.headers.setdefault("content-length", content_length) self.headers.setdefault("last-modified", last_modified)