Built-in middleware =================== CORS ---- `CORS (Cross-Origin Resource Sharing) `_ is a common security mechanism that is often implemented using middleware. To enable CORS in a litestar application simply pass an instance of :class:`~litestar.config.cors.CORSConfig` to :class:`~litestar.app.Litestar`: .. code-block:: python from litestar import Litestar from litestar.config.cors import CORSConfig cors_config = CORSConfig(allow_origins=["https://www.example.com"]) app = Litestar(route_handlers=[...], cors_config=cors_config) CSRF ---- `CSRF (Cross-site request forgery) `_ is a type of attack where unauthorized commands are submitted from a user that the web application trusts. This attack often uses social engineering that tricks the victim into clicking a URL that contains a maliciously crafted, unauthorized request for a particular Web application. The user’s browser then sends this maliciously crafted request to the targeted Web application. If the user is in an active session with the Web application, the application treats this new request as an authorized request submitted by the user. Thus, the attacker can force the user to perform an action the user didn't intend, for example: .. code-block:: text POST /send-money HTTP/1.1 Host: target.web.app Content-Type: application/x-www-form-urlencoded amount=1000usd&to=attacker@evil.com This middleware prevents CSRF attacks by doing the following: 1. On the first "safe" request (e.g GET) - set a cookie with a special token created by the server 2. On each subsequent "unsafe" request (e.g POST) - make sure the request contains either a form field or an additional header that has this token (more on this below) To enable CSRF protection in a Litestar application simply pass an instance of :class:`~litestar.config.csrf.CSRFConfig` to the Litestar constructor: .. code-block:: python from litestar import Litestar, get, post from litestar.config.csrf import CSRFConfig @get() async def get_resource() -> str: # GET is one of the safe methods return "some_resource" @post("{id:int}") async def create_resource(id: int) -> bool: # POST is one of the unsafe methods return True csrf_config = CSRFConfig(secret="my-secret") app = Litestar([get_resource, create_resource], csrf_config=csrf_config) The following snippet demonstrates how to change the cookie name to ``"some-cookie-name"`` and header name to ``"some-header-name"``. .. code-block:: python csrf_config = CSRFConfig(secret="my-secret", cookie_name='some-cookie-name', header_name='some-header-name') A CSRF protected route can be accessed by any client that can make a request with either the header or form-data key. .. note:: The form-data key can not be currently configured. It should only be passed via the key ``"_csrf_token"`` In Python, any client such as `requests `_ or `httpx `_ can be used. The usage of clients or sessions is recommended due to the cookie persistence it offers across requests. The following is an example using `httpx.Client `_. .. code-block:: python import httpx with httpx.Client() as client: get_response = client.get("http://localhost:8000/") # "csrftoken" is the default cookie name csrf = get_response.cookies["csrftoken"] # "x-csrftoken" is the default header name post_response_using_header = client.post("http://localhost:8000/1", headers={"x-csrftoken": csrf}) assert post_response_using_header.status_code == 201 # "_csrf_token" is the default *non* configurable form-data key post_response_using_form_data = client.post("http://localhost:8000/1", data={"_csrf_token": csrf}) assert post_response_using_form_data.status_code == 201 # despite the header being passed, this request will fail as it does not have a cookie in its session # note the usage of ``httpx.post`` instead of ``client.post`` post_response_with_no_persisted_cookie = httpx.post("http://localhost:8000/1", headers={"x-csrftoken": csrf}) assert post_response_with_no_persisted_cookie.status_code == 403 assert "CSRF token verification failed" in post_response_with_no_persisted_cookie.text Routes can be marked as being exempt from the protection offered by this middleware via :ref:`handler opts ` .. code-block:: python @post("/post", exclude_from_csrf=True) def handler() -> None: ... If you need to exempt many routes at once you might want to consider using the :attr:`~litestar.config.csrf.CSRFConfig.exclude` kwarg which accepts list of path patterns to skip in the middleware. .. seealso:: * `Safe and Unsafe (HTTP Methods) `_ * `HTTPX Clients `_ * `Requests Session `_ Allowed Hosts ------------- Another common security mechanism is to require that each incoming request has a ``"Host"`` or ``"X-Forwarded-Host"`` header, and then to restrict hosts to a specific set of domains - what's called "allowed hosts". Litestar includes an :class:`~litestar.middleware.allowed_hosts.AllowedHostsMiddleware` class that can be easily enabled by either passing an instance of :class:`~litestar.config.allowed_hosts.AllowedHostsConfig` or a list of domains to :class:`~litestar.app.Litestar`: .. code-block:: python from litestar import Litestar from litestar.config.allowed_hosts import AllowedHostsConfig app = Litestar( route_handlers=[...], allowed_hosts=AllowedHostsConfig( allowed_hosts=["*.example.com", "www.wikipedia.org"] ), ) .. note:: You can use wildcard prefixes (``*.``) in the beginning of a domain to match any combination of subdomains. Thus, ``*.example.com`` will match ``www.example.com`` but also ``x.y.z.example.com`` etc. You can also simply put ``*`` in trusted hosts, which means allow all. This is akin to turning the middleware off, so in this case it may be better to not enable it in the first place. You should note that a wildcard can only be used in the prefix of a domain name, not in the middle or end. Doing so will result in a validation exception being raised. Compression ----------- HTTP responses can optionally be compressed. Litestar has support for gzip, brotli, and zstd. Gzip is supported by Litestar out of the box, while Brotli support can be added by installing the ``brotli`` extra, and Zstd support can be added by installing the ``zstd`` extra. You can enable any one of these backends by passing an instance of :class:`~litestar.config.compression.CompressionConfig` to ``compression_config`` of :class:`~litestar.app.Litestar`. GZIP ^^^^ You can enable gzip compression of responses by passing an instance of :class:`~litestar.config.compression.CompressionConfig` with the ``backend`` parameter set to ``"gzip"``. You can configure the following additional gzip-specific values: * ``minimum_size``: the minimum threshold for response size to enable compression. Smaller responses will not be compressed. Default is ``500``, i.e. half a kilobyte. * ``gzip_compress_level``: a range between 0-9, see the `official python docs `_. Defaults to ``9``, which is the maximum value. .. code-block:: python from litestar import Litestar from litestar.config.compression import CompressionConfig app = Litestar( route_handlers=[...], compression_config=CompressionConfig(backend="gzip", gzip_compress_level=9), ) Brotli ^^^^^^ The `Brotli `_ package is required to run this middleware. It is available as an extras to litestar with the ``brotli`` extra (``pip install 'litestar[brotli]'``). You can enable brotli compression of responses by passing an instance of :class:`~litestar.config.compression.CompressionConfig` with the ``backend`` parameter set to ``"brotli"``. You can configure the following additional brotli-specific values: * ``minimum_size``: the minimum threshold for response size to enable compression. Smaller responses will not be compressed. Default is 500, i.e. half a kilobyte * ``brotli_quality``: Range [0-11], Controls the compression-speed vs compression-density tradeoff. The higher the quality, the slower the compression. Defaults to 5 * ``brotli_mode``: The compression mode can be ``"generic"`` (for mixed content), ``"text"`` (for UTF-8 format text input), or ``"font"`` (for WOFF 2.0). Defaults to ``"text"`` * ``brotli_lgwin``: Base 2 logarithm of size. Range [10-24]. Defaults to 22. * ``brotli_lgblock``: Base 2 logarithm of the maximum input block size. Range [16-24]. If set to 0, the value will be set based on the quality. Defaults to 0 * ``brotli_gzip_fallback``: a boolean to indicate if gzip should be used if brotli is not supported .. code-block:: python from litestar import Litestar from litestar.config.compression import CompressionConfig app = Litestar( route_handlers=[...], compression_config=CompressionConfig(backend="brotli", brotli_gzip_fallback=True), ) Zstd ^^^^^^ The `backports.zstd `_ package is required to run this middleware. It is available as an extra for Litestar via the ``zstd`` extra: (``pip install 'litestar[zstd]'``). You can enable zstd compression of responses by passing an instance of :class:`~litestar.config.compression.CompressionConfig` with the ``backend`` parameter set to ``"zstd"``. You can configure the following additional zstd-specific values: * ``minimum_size``: the minimum threshold for response size to enable compression. Smaller responses will not be compressed. Default is 500, i.e. half a kilobyte. * ``zstd_compress_level``: Integer >= 0. Controls the compression level. Higher values increase compression ratio but are slower. A value of 0 indicates use of the library default, which is typically level 3. Default is 0. * ``zstd_gzip_fallback``: Boolean indicating whether to fall back to gzip if Zstd is not supported. Default is True. .. code-block:: python from litestar import Litestar from litestar.config.compression import CompressionConfig app = Litestar( route_handlers=[...], compression_config=CompressionConfig(backend="zstd", zstd_gzip_fallback=True), ) Rate-Limit Middleware --------------------- Litestar includes an optional :class:`~litestar.middleware.rate_limit.RateLimitMiddleware` that follows the `IETF RateLimit draft specification `_. To use the rate limit middleware, use the :class:`~litestar.middleware.rate_limit.RateLimitConfig`: .. literalinclude:: /examples/middleware/rate_limit.py :language: python The only required configuration kwarg is ``rate_limit``, which expects a tuple containing a time-unit (``"second"``, ``"minute"``, ``"hour"``, ``"day"``\ ) and a value for the request quota (integer). Using behind a proxy ^^^^^^^^^^^^^^^^^^^^ The default mode for uniquely identifiying client uses the client's address. When an application is running behind a proxy, that address will be the proxy's, not the "real" address of the end-user. While there are special headers set by proxies to retrieve the remote client's actual address (``X-FORWARDED-FOR``), their values should not implicitly be trusted, as any client is free to set them to whatever value they want. A rate-limit could easily be circumvented by spoofing these, and simply attaching a new, random address to each request. The best way to handle applications running behind a proxy is to use a middleware that updates the client's address in a secure way, such as uvicorn's `ProxyHeaderMiddleware `_ or hypercon's `ProxyFixMiddleware `_ . Logging Middleware ------------------ This content has moved to :doc:`/usage/logging` Session Middleware ------------------ Litestar includes a :class:`~litestar.middleware.session.base.SessionMiddleware`, offering client- and server-side sessions. Server-side sessions are backed by Litestar's :doc:`stores `, which offer support for: - In memory sessions - File based sessions - Redis based sessions - Valkey based sessions Setting up the middleware ^^^^^^^^^^^^^^^^^^^^^^^^^ To start using sessions in your application all you have to do is create an instance of a :class:`configuration ` object and add its middleware to your application's middleware stack: .. literalinclude:: /examples/middleware/session/cookies_full_example.py :caption: Hello World :language: python .. note:: Since both client- and server-side sessions rely on cookies (one for storing the actual session data, the other for storing the session ID), they share most of the cookie configuration. A complete reference of the cookie configuration can be found at :class:`~litestar.middleware.session.base.BaseBackendConfig`. Client-side sessions ^^^^^^^^^^^^^^^^^^^^ Client side sessions are available through the :class:`~litestar.middleware.session.client_side.ClientSideSessionBackend`, which offers strong AES-CGM encryption security best practices while support cookie splitting. .. important:: ``ClientSideSessionBackend`` requires the `cryptography `_ library, which can be installed together with litestar as an extra using ``pip install 'litestar[cryptography]'`` .. literalinclude:: /examples/middleware/session/cookie_backend.py :caption: ``cookie_backend.py`` :language: python .. seealso:: * :class:`~litestar.middleware.session.client_side.CookieBackendConfig` Server-side sessions ^^^^^^^^^^^^^^^^^^^^ Server side session store data - as the name suggests - on the server instead of the client. They use a cookie containing a session ID which is a randomly generated string to identify a client and load the appropriate data from the store .. literalinclude:: /examples/middleware/session/file_store.py .. seealso:: * :doc:`/usage/stores` * :class:`~litestar.middleware.session.server_side.ServerSideSessionConfig`