wagtail / bakerydemo

Next generation Wagtail demo, born in Reykjavik

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CSP testing setup

thibaudcolas opened this issue · comments

Part of #1288 CSP compatibility issues. We need a basic opt-in setup on the bakerydemo so we can try out different degrees of CSP strictness (see also #232). This will simplify the process for contributors to make improvements to CSP support.

Here are my thoughts on the setup but this is very much not something I’m knowledgeable about so will need guidance from others:

  • This could be set up with the Content-Security-Policy-Report-Only header for now, so we can iterate on CSP support without disrupting demo site usage.
  • Either with django-csp or from scratch
  • Ideally in a way that’s configurable easily so we can try different levels of strictness (unsafe-eval, unsafe-inline, script-dynamic)

It’d be great for the default configuration to be one we could recommend for Wagtail sites, but if that seems too tricky, any configuration will be better than nothing.

For reference, this is what Torchbox projects do as a baseline, with django-csp:

# Content Security policy settings
# http://django-csp.readthedocs.io/en/latest/configuration.html
if "CSP_DEFAULT_SRC" in env:
    MIDDLEWARE.append("csp.middleware.CSPMiddleware")

    # The “special” source values of 'self', 'unsafe-inline', 'unsafe-eval', and 'none' must be quoted!
    # e.g.: CSP_DEFAULT_SRC = "'self'" Without quotes they will not work as intended.

    CSP_DEFAULT_SRC = env.get("CSP_DEFAULT_SRC").split(",")
    if "CSP_SCRIPT_SRC" in env:
        CSP_SCRIPT_SRC = env.get("CSP_SCRIPT_SRC").split(",")
    if "CSP_STYLE_SRC" in env:
        CSP_STYLE_SRC = env.get("CSP_STYLE_SRC").split(",")
    if "CSP_IMG_SRC" in env:
        CSP_IMG_SRC = env.get("CSP_IMG_SRC").split(",")
    if "CSP_CONNECT_SRC" in env:
        CSP_CONNECT_SRC = env.get("CSP_CONNECT_SRC").split(",")
    if "CSP_FONT_SRC" in env:
        CSP_FONT_SRC = env.get("CSP_FONT_SRC").split(",")
    if "CSP_BASE_URI" in env:
        CSP_BASE_URI = env.get("CSP_BASE_URI").split(",")
    if "CSP_OBJECT_SRC" in env:
        CSP_OBJECT_SRC = env.get("CSP_OBJECT_SRC").split(",")

And the more opinionated variant we’re hoping to have soon:

CSP_DEFAULT_SRC = ["'self'", "'unsafe-inline'"]
CSP_IMG_SRC = ["'self'", "data:"]
CSP_UPGRADE_INSECURE_REQUESTS = True
CSP_SANDBOX = True

# Allow retrieving images from the custom S3 domain if it exists
if "AWS_S3_CUSTOM_DOMAIN" in env:
    CSP_IMG_SRC.append(env["AWS_S3_CUSTOM_DOMAIN"])

I think the plan makes sense to me. Using django-csp should be absolutely fine. I think it makes sense to use report-only in the beginning, but will also need an URL where it can report to using the report-to directive. Then one can check the json violation reported. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only#violation_report_syntax is a good reference for the violation reporting syntaxes.

With the different levels, I think it's easy when we think of just 'self' and 'unsafe-inline' and similar ones, but gets trickier when we consider nonce and external URLs that might be needed as well. If we are just going to configure the CSP directives and not have pre-defined strictness like "strict", "unsafe", etc. then I think just using environment variables and django-csp is good enough. I won't know how to recommend same CSP for all wagtail sites. We can rather recommend what not to do, as in avoid unsafe-inline, unsafe-eval, etc.

The main reason Wagtail isn't CSP compatible stems from the use of injected script tags in the admin. If we can remove those, things get much simpler.

There are a few other remote resources Wagtail depends on, such as the version check in releases.wagtail.org and gravatar, but those are fairly static and easy to document. Other than the basics of self, there shouldn't be much more that Wagtail itself needs to function.

The above "opinionated" option will work with Wagtail today, and technically enforces CSP. The problem is that it's not very strong in its use of unsafe-inline, as it allows any script tags in the HTML, which can open up XSS issues. That's the main directive we want to remove. The first example doesn't configure django-csp at all, only allowing it to be configured through the environment.

I think for a wagtail dev site, we should just enforce CSP, and see where it breaks. Adding django-csp to bakerydemo and to our nightly environments would let us easily achieve this.

Done in #232.

I know this is a closed issue but wanted to ask how an enforced CSP will affect browser tools such as screen readers for accessibility. Depending on the policy chosen you might find a large number of false positives being reported (and of course blocked if Report-Only is removed). Adding this here as a note for the experimentation process when trying 'different degrees of CSP strictness' unless of course someone already know the answer to this.

@danielabrahamsgosh it’s completely fine to comment even if already closed! Could you expand upon your question? As far as I know screen readers shouldn’t be affected by CSPs at all. Browser extensions which inject content onto sites would break, but that is generally the intention – and those extensions which do want to bypass the CSP have APIs to do so.

Thanks @thibaudcolas - I understand about screen readers specifically. My question is more general about how a CSP can affect accessibility tools across the spectrum (as this is something I would not want to block). I could think of a multitude of systems for example an extension that changes colours on a site to make it easier to read. What I am not sure about is what is considered 'standard' in the industry. I am certainly not an accessibility specialist and will need to research the CSP APIs you mention.

It was simply a worry I had retrospectively after implementing a CSP but I haven't had the time to research it fully yet. We are still on the report-only phase of implementation and I have seen some possible reports from 'the wild' I cannot account for. If the participants in this conversation don't deem it a risk that would be good enough for me. Many thanks!

@danielabrahamsgosh as far as I’m aware, though it’s possible for accessibility-related browser extensions to be affected if implemented poorly, they have dedicated browser APIs which aren’t affected by the CSP. For example APIs to insert scripts or CSS onto the page without having to follow the CSP. It’s something extension developers can take into account but as far as I know they do (otherwise lots of extensions would be broken on lots of websites).

@danielabrahamsgosh accessibility tools such as NVDA or VoiceOver sit outside the browser so they would not impacted with any CSP changes.

Browser plug-ins like ChromeVox or Wave accessibility checkers can also sit outside the scope/remit of CSP.

CSP is about code provided from the sites server, and third party scripts.