- Affected components: MediaWiki core and its CSP feature.
- Initial implementation: TBD.
- Code stewards: TBD.
Motivation
RFC T135963 has provided the fundamentals of the CSP infrastructure in MediaWiki core. We can configure the CSP header, toggle whether to report-only or enforce, and send/receive violations via a new API module, and more.
Originally I had planned to write an additional public RFC on the user opt-out method of Content Security Policy on Wikimedia. Since the original RFC, a number of things have changed:
- A re-focus to first focus on forbidding external scripts, rather than concentrating on the anti-XSS provisions of CSP
- A recent string of account compromises using external scripts has caused security team to expedite deploying CSP in report only mode in order to gain logging insight into external scripts that are being loaded.
With that in mind, the new threat model we are trying to address in the near-term with CSP is:
- Privacy protection: Prevent both malicious and accidental privacy leaks by preventing loading third-party resources (e.g. Prevent the helpful interface-admin who doesn't realize the implications of putting google analytics into the site JS)
- Force people who attack our sites with malicious javascript (e.g. by taking over an interface-admin account and editing MediaWiki:Common.js) to place all malicious JS on-site so that we can determine exactly what the attacker was doing after the fact.
We believe concentrating solely on preventing third party resource usage will be a much easier transition for the community and also provide significant immediate benefits in terms of security and privacy. We are still very much interested in the anti-XSS measures of CSP (e.g. banning 'unsafe-inline'), but intend to leave that to the distant future for now.
There's also some on-wiki notes about this at https://www.mediawiki.org/wiki/User:BWolff_(WMF)/CSP_plan
Requirements
Before we can go fully into enforce mode for all users, we need to address the needs of gadgets that communicate with external APIs. This is a common use case on wikis today. Often this is Cloud VPS/Toolforge (See counter vandalism network. There are several others). While we intend to fully ban loading external scripts, allowing external API access to send/receive data on an opt-in basis is a totally reasonable thing for users to want.
- A gadget can only load data from external APIs that the user opted-in for.
- User opt-in must be on a per-origin basis.
- The allowance is only for sending and receiving data. Not for importing executable JavaScript code.
- The allowances need to be stored somewhere per-user.
- The core CSP mechanism needs to read these out and add the necessary exemptions to the CSP header on each relevant page view.
Exploration
I propose adding a special page which allows users to add a list of domains to include in the default-src directive of their CSP rule. The reason not to use a user preference is that I think changing this value should require re-authentication, as adjusting it would be useful to a malicious person.
This would only modify default-src and not script-src. So people still would only be able to directly load wikimedia sources via importScript() and friends. However as we are not prepared at this time to disable eval() and variants, people could still get around this if they wanted to. I hope banning external JS in script-src will at least discourage this practise, and perhaps in some glorious future we will be able to get rid of unsafe-eval and unsafe-inline. That is undoubtedly a long way off.
This will be backed by a custom DB table that lives in the centralauth DB (Thus it will be a global option).
The schema for this table will be something like:
CREATE TABLE /*_*/csp_sources ( csp_user unsigned int NOT NULL, csp_domain VARBINARY(255) NOT NULL, csp_timestamp BINARY(14) NOT NULL );
There's some question as to what the allowed values should be. Originally I envisioned this as a simple checkbox that would add * to the default-src value, allowing access to the entire internet. Upon further reflection, I think we should discourage users from doing that. Forcing users to input specific domains reduces the potential risk to the specific domains they actually use. It also means it is less likely for a wide number of users to all use the same domain, meaning an attacker won't be able to just compromise a single domain to target all the opted-out users. Thus I would like to require users to input specific domains, and furthermore in the case of Cloud VPS they wouldn't be allowed to specify *.wmflabs.org but instead must specify someproject.wmflabs.org. In the case of toolforge, they would have to specify a path, so tools.wmflabs.org/bawolff/ and not simply tools.wmflabs.org.
Thanks, I appreciate feedback on this proposal.