Manual:$wgCSPHeader

From mediawiki.org
Security: $wgCSPHeader
Controls Content-Security-Policy header [Experimental]
Introduced in version:1.32.0 (Gerrit change 253969; git #70941efd)
Removed in version:still in use
Allowed values:(boolean or array)
Default value:false

This config variable allows you to enable the Content-Security-Policy header. This header can help to keep your site secure from XSS attacks, and reduce the risk of certain kind of privacy leaks. Support for this is still experimental in MediaWiki, and comes with many caveats that reduce the amount of protection this feature provides.

As an anti-XSS measure[edit]

If the nonce part of this feature is enabled (See below), it can make it much more challenging to exploit cross-site scripting (XSS) vulnerabilities in your site. Certain types of XSS may even be impossible to exploit with this feature enabled.

It works by requiring a secret value (a "nonce") that changes every request, in order to execute. For example, consider if you had $wgRawHtml set to true (You would probably never combine this feature with raw html as it defeats the point, but it serves as a good example). If you wanted to run a script, you would put <html><script>alert( 'Do Evil!' );</script></html> on the page. This feature prevents things like that from working, by requiring all ‎<script> tags to have a nonce attribute, e.g. <script nonce="UsfKQXiytSex1OdwUk76">. The nonce has to match the nonce supplied in an http header, and changes on every request. Thus you would no longer be able to run a script by writing something on to a wikipage, as once you hit save, the nonce changes.

It also disables the javascript: url scheme in links, and all the attributes starting with on in html (So you can no longer do html like <img src=x onerror="alert('do evil');">.

All user and site JS (If $wgAllowUserJs and/or $wgUseSiteJs is true) are unaffected, as long as they don't use javascript: uri schemes or inject html (e.g. via innerHTML) that contains attributes starting with on.

Caveats:

  • This won't protect against certain type of Dom-XSS. Whether or not it protects against a Dom-XSS depends on the specifics of the vulnerability
    • In particular, MediaWiki generally doesn't allow users to create attributes starting with data-mw or data-ooui (See phab:T105413). An XSS that allows bypassing this restriction wouldn't be stopped by this feature, although it may still make it harder to exploit by banning inline event attributes and javascript URI's.
  • At this time, it doesn't prevent loading user JS. If an attacker is able to inject html this can essentially be bypassed by loading a user JS page controlled by the attacker. Notwithstanding, its still helpful as it forces the attacker to leave an audit trail, and in many cases the attacker may not be able to load a script tag but is only able to add attributes to existing html, which would be blocked by this. Disabling $wgAllowUserJs stops attackers from being able to load user JS through resource loader. For action=raw&ctype=text/javascript, it can be disabled via $wgHooks['RawPageViewBeforeOutput'][] = function ( $rp, &$content ) { if ( $rp->getContentType() === 'text/javascript' ) $content = 'console.log( "JS raw actions disabled" )';};
  • If front-end caching (varnish) is used, logged out users will have nonces repeat on cached page views. This reduces the security provided by this feature. The feature still helps, as logged in users are the most likely to be attacked (Since they have valuable accounts) and they would have full protection of the feature. It would also still protect against persistent XSS for the most part, as the act of saving a page would change the nonce. However protection against reflected XSS for logged out users would be rather limited.
  • It is not compatible with $wgUseFileCache
  • For best security, it is recommended that you do not have Angular js files anywhere on your webserver or any of the domains that script-src is configured to allow, as it can be used to bypass CSP restrictions.
  • JSONP endpoints can sometimes be used to bypass CSP restrictions. MediaWiki comes with one by default [1]. It only allows ascii letters, numbers, _, ', ", ., [, ] in the callback name, which makes it very difficult to exploit, but in principle there could be situations where it could be used to bypass CSP.
  • Some extensions might not be compatible with this feature, but most should just work.

As a data-leak prevention measure[edit]

CSP allows you to define what urls the page is allowed to access. This can be used to help protect user privacy. At this point in time, this is more against accidental mistakes, as there are bypasses that a malicious person could use to leak data cross-domain if they can execute scripts (phab:T238367).

If a domain is access not in the allow list, the browser stops the access and (optionally) sends a report.

The motivating use case for this feature is Wikimedia wikis, where we allow user javascript, but we don't want that user js to be loading random things from the internet, as that would violate the privacy policy.

If using the anti-xss feature it is important to carefully define script-src, as any javascript (including malicious) from a script-src can still be used.

Config value[edit]

Keep in mind, extensions may add their own things. MediaWiki should automatically add anything that it itself needs.

If its false - disable feature and do nothing.

If its true, equivalent to setting it to []. At the moment, this means: require nonce, limit scripts to coming from the current domain, allow everything else (default-src of *)

If an array, the following keys are recognized

  • 'default-src' If true or array (of additional urls) will set a default-src directive, which limits what places things can load from. If false or not set, will send a default-src directive allowing all sources. If you want a restrictive default, just set it to the empty array.
  • 'includeCORS' If true or not set, will include urls from $wgCrossSiteAJAXdomains as an allowed load sources unless default-src is already *.
  • 'unsafeFallback' Add unsafe-inline as a script source, as a fallback for browsers that do not understand nonce-sources [default on].
  • 'useNonces' Require nonces on all inline scripts. If disabled and 'unsafeFallback' is on, then all inline scripts will be allowed [default true].
  • 'script-src' Array of additional places that are allowed to have JS be loaded from.
  • 'report-uri' true to use MW api [default], false to disable, string for alternate uri. Set $wgDebugLogGroups['csp'] to record these.

In any of the src directives, you can use domain names with or without protocols, and also wildcards as the leftmost subdomain. For example, the following are valid for script-src and default-src: example.com, *.example.com, http://example.com, https://example.com, https://example.com/foo.png

Examples[edit]

If you want to enable this for security reasons (nonces), but still want to allow loading images, etc from anywhere:

$wgCSPHeader = true;

If you want to be more restrictive, enabling both the security features, and disallowing loading resources from third party domains

$wgCSPHeader = [
    'default-src' => []
];

If you want to be restrictive, but have a friendly site friend.example.com that you want to allow loading resources (images, styles, fonts, etc) from but not scripts:

$wgCSPHeader = [
    'default-src' => [ 'friend.example.com' ]
];

If you want to be able to both load resources and scripts from any subdomain of example.com:

$wgCSPHeader = [
    'script-src' => [ '*.example.com' ],
    'default-src' => [ '*.example.com' ]
];


If you want to restrict where you can load resources and scripts from, but you want to disable the anti-xss (nonce) feature:

$wgCSPHeader = [
    'useNonces' => false,
    'default-src' => []
];


See also[edit]