Using the generated CSP nonce

When NONCE is included in a directive, the nonce value is returned in the CSP headers if it is used, e.g. by evaluating the nonce in your template. To actually make the browser do anything with this value, you will need to include it in the attributes of the tags that you wish to mark as safe.

Note

Use view source on a page to see nonce values. Nonce values are not visible in browser developer tools. To prevent malicious CSS selectors leaking the values, they are not exposed to the DOM.

Middleware

Installing the middleware creates a lazily evaluated property csp_nonce and attaches it to all incoming requests.

MIDDLEWARE = (
    # ...
    "csp.middleware.CSPMiddleware",
    # ...
)

This value can be accessed directly on the request object in any view or template and manually appended to any script element like so -

<script nonce="{{request.csp_nonce}}">
        var hello="world";
</script>

Assuming the NONCE sentinel is included in the script-src directive, this will result in the above script being allowed.

Note

The nonce will only be included in the CSP header if:

  • csp.constants.NONCE is present in the script-src or style-src directives, and

  • request.csp_nonce is accessed during the request lifecycle, after the middleware processes the request but before it processes the response.

The csp.middleware.CSPMiddleware will include the nonce in the CSP header as it processes the response, but only if it was generated by code reading str(request.csp_nonce).

If code reads an un-generated request.csp_nonce after the middleware processes the response, it is probably a programming error. In this case, attempting to read the nonce (like str(request.csp_nonce)) will raise a csp.exceptions.CSPNonceError. If the nonce was generated and included in the CSP header, then reading request.csp_nonce is safe.

It is always safe to test request.csp_nonce, such as bool(request.csp_nonce) or in a conditional like if request.csp_nonce: .... This will return True if the nonce was accessed and generated, and False if not acccesed or generated yet.

If other middleware or a later process needs to access request.csp_nonce, then there are a few options:

  • The middleware can be placed after csp.middleware.CSPMiddleware in the MIDDLEWARE setting. This ensures that the middleware generates the nonce before CSPMiddleware writes the CSP header.

  • Add a later middleware that accesses the nonce. For example, this function:

def init_csp_nonce_middleware(get_response):
    def middleware(request):
        str(getattr(request, "csp_nonce", None))
        return get_response(request)

    return middleware

could be added to the MIDDLEWARE list:

MIDDLEWARE = (
    "my.middleware.ThatUsesCSPNonce",
    # ...
    "csp.middleware.CSPMiddleware",
    # ...
    "my.middleware.init_csp_nonce_middleware",
)

Context Processor

This library contains an optional context processor, adding csp.context_processors.nonce to your configured context processors exposes a variable called CSP_NONCE into the global template context. This is simple shorthand for request.csp_nonce, but can be useful if you have many occurrences of script tags.

<script nonce="{{CSP_NONCE}}">
    var hello="world";
</script>

Django Template Tag/Jinja Extension

Note

If you’re making use of csp.extensions.NoncedScript you need to have jinja2>=2.9.6 installed, so please make sure to either use django-csp[jinja2] in your requirements or define it yourself.

It can be easy to forget to include the nonce property in a script tag, so there is also a script template tag available for both Django templates and Jinja environments.

This tag will output a properly nonced script every time. For the sake of syntax highlighting, you can wrap the content inside of the script tag in <script> html tags, which will be subsequently removed in the rendered output. Any valid script tag attributes can be specified and will be forwarded into the rendered html.

Django Templates

Add the CSP template tags to the TEMPLATES section of your settings file:

TEMPLATES = [
    {
        "OPTIONS": {
            "libraries": {
                "csp": "csp.templatetags.csp",
            }
        }
    }
]

Then load the csp template tags and use script in the template:

{% load csp %}
{% script type="application/javascript" async=False %}
        <script>
                var hello='world';
        </script>
{% endscript %}

Jinja

Add csp.extensions.NoncedScript to the TEMPLATES section of your settings file:

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.jinja2.Jinja2",
        "OPTIONS": {
            "extensions": [
                "csp.extensions.NoncedScript",
            ],
        },
    }
]
{% script type="application/javascript" async=False %}
        <script>
                var hello='world';
        </script>
{% endscript %}

Both templates output the following with a different nonce:

<script nonce='123456' type="application/javascript" async=false>var hello='world';</script>