pallets-eco / cachelib

Extract from werkzeug.cache
BSD 3-Clause "New" or "Revised" License
134 stars 44 forks source link

FIPS Compliance #361

Closed jtrinh27 closed 3 months ago

jtrinh27 commented 4 months ago

Leveraging this Library in a FIPS Enforced environment causes the application using this library to be halted. Although the use of md5 here is valid, it is caught by the FIPS Enforced environment. https://github.com/pallets-eco/cachelib/blob/18bb52cc29a07f7f0d7992d682d769f3497851b4/src/cachelib/file.py#L50

davidism commented 4 months ago

Need to somehow make this lazy, the issue is that hashlib.md5 doesn't exist in FIPS mode, so it raises an exception on attribute access before it's possible to change the default in user code.

northernSage commented 3 months ago

how about moving to sha256? That should be a compliant alternative 🤔

aenglander commented 3 months ago

Changing the default would be a breaking change. I suggest passing a hash method like the FileSystemCache and lazy loading the default. There's no guarantee that any internal function will be FIPS-compliant. Passing the hash function would allow using an external FIPS-compliant hashing function if necessary.

davidism commented 3 months ago

I have a lazy loading fix for flask/itsdangerous, I'll ping here once I get that in there.

northernSage commented 3 months ago

I'll get the ball rolling, maybe something simple like:

class FileSystemCache(BaseCache):
    # ...
    def __init__(
        ...
        hash_method: _t.Any = None,
    ):
        # ...
        self._hash_method = hash_method

        if hash_method is None:
            try:
                from hashlib import md5
            except ImportError as err:
                raise RuntimeError(
                    "could not import hashlib.md5 "
                    "alternative hashing methods may be used by passing 'hash_method' initialization parameter "
                ) from err
            else:
                self._hash_method = md5
davidism commented 3 months ago

I just did this in Flask, and will add it to itsdangerous as well: https://github.com/pallets/flask/pull/5460/files Basically write a wrapper that accesses hashlib.md5 internally, so it's not accessed at import time. Then you can continue to use MD5 here and allow people to override it.

def _lazy_md5(string: bytes = b"") -> t.Any:
    return hashlib.md5(string)

hash_method=_lazy_md5
northernSage commented 3 months ago

cool, will use this to set the default. Thanks all for the help!