Security¶
This page contains some security recommendations and guidelines for advanced use cases.
Pickle Vulnerabilities¶
Warning
The python pickle module has known security vulnerabilities,
potentially leading to code execution when deserializing data.
This means it should only be used to deserialize data that you trust hasn’t been tampered with.
Safe Pickling With Untrusted Data¶
If you’re working with untrusted data, consider using one of the other supported Serializers instead of pickle.
Since this isn’t always possible, requests-cache can optionally use itsdangerous to add a layer of security around these operations. It works by signing serialized data with a secret key that you control. Then, if the data is tampered with, the signature check fails and raises an error.
Optional dependencies can be installed with:
pip install itsdangerous
Creating and Storing a Secret Key¶
To enable this behavior, first create a secret key, which can be any str or bytes object.
One common pattern for handling this is to store it wherever you store the rest of your credentials (Linux keyring, macOS keychain, password database, etc.), set it in an environment variable, and then read it in your application:
>>> import os
>>> secret_key = os.environ['SECRET_KEY']
Alternatively, you can use the keyring package to read the key directly:
>>> import keyring
>>> secret_key = keyring.get_password('requests-cache-example', 'secret_key')
Signing Cached Responses¶
Once you have your key, create a safe_pickle_serializer() with it:
>>> from requests_cache import CachedSession, safe_pickle_serializer
>>> serializer = safe_pickle_serializer(secret_key=secret_key)
>>> session = CachedSession(serializer=serializer)
>>> session.get('https://httpbin.org/get')
Note
You can also make your own Custom Serializers, if you would like more control over how responses are serialized.
You can verify that it’s working by modifying the cached item (without your key):
>>> serializer_2 = safe_pickle_serializer(secret_key='a different key')
>>> session_2 = CachedSession(serializer=serializer_2)
>>> cache_key = list(session_2.cache.responses.keys())[0]
>>> session_2.cache.responses[cache_key] = 'exploit!'
Then, if you try to get that cached response again (with your key), you will get an error:
>>> session.get('https://httpbin.org/get')
BadSignature: Signature b'iFNmzdUOSw5vqrR9Cb_wfI1EoZ8' does not match