From 35023d616fb75a4c3b7a58f04b16d22e81a7403b Mon Sep 17 00:00:00 2001 From: Brian Wolff Date: Thu, 27 Sep 2018 11:42:37 +0000 Subject: [PATCH] SECURITY: Don't allow loading unprotected JS files This is meant to protect against malicious people while avoiding annoying good users as much as possible. We may want to restrict this further in the future, but that's something that can be discussed in the normal way. Bug: T194204 Bug: T113042 Bug: T112937 Change-Id: I27e049bae78b5c0f63b10f454b740cb1dc394813 --- includes/actions/RawAction.php | 24 ++++++++++++++++++++++++ languages/i18n/en.json | 3 ++- languages/i18n/qqq.json | 3 ++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/includes/actions/RawAction.php b/includes/actions/RawAction.php index b5a6d3ac25..77a8b14e2c 100644 --- a/includes/actions/RawAction.php +++ b/includes/actions/RawAction.php @@ -129,6 +129,30 @@ class RawAction extends FormlessAction { } } + // Don't allow loading non-protected pages as javascript. + // In future we may further restrict this to only CONTENT_MODEL_JAVASCRIPT + // in NS_MEDIAWIKI or NS_USER, as well as including other config types, + // but for now be more permissive. Allowing protected pages outside of + // NS_USER and NS_MEDIAWIKI in particular should be considered a temporary + // allowance. + if ( + $contentType === 'text/javascript' && + !$title->isUserJsConfigPage() && + !$title->inNamespace( NS_MEDIAWIKI ) && + !in_array( 'sysop', $title->getRestrictions( 'edit' ) ) && + !in_array( 'editprotected', $title->getRestrictions( 'edit' ) ) + ) { + + $log = LoggerFactory::getInstance( "security" ); + $log->info( "Blocked loading unprotected JS {title} for {user}", + [ + 'user' => $this->getUser()->getName(), + 'title' => $title->getPrefixedDBKey(), + ] + ); + throw new HttpError( 403, wfMessage( 'unprotected-js' ) ); + } + $response->header( 'Content-type: ' . $contentType . '; charset=UTF-8' ); $text = $this->getRawText(); diff --git a/languages/i18n/en.json b/languages/i18n/en.json index 5283a5bb06..e35af5a36a 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -4519,5 +4519,6 @@ "passwordpolicies-policy-passwordcannotmatchblacklist": "Password cannot match specifically blacklisted passwords", "passwordpolicies-policy-maximalpasswordlength": "Password must be less than $1 {{PLURAL:$1|character|characters}} long", "passwordpolicies-policy-passwordcannotbepopular": "Password cannot be {{PLURAL:$1|the popular password|in the list of $1 popular passwords}}", - "easydeflate-invaliddeflate": "Content provided is not properly deflated" + "easydeflate-invaliddeflate": "Content provided is not properly deflated", + "unprotected-js": "For security reasons JavaScript cannot be loaded from unprotected pages. Please only create javascript in the MediaWiki: namespace or as a User subpage" } diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index a17cfca049..cbee32b046 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -4721,5 +4721,6 @@ "passwordpolicies-policy-passwordcannotmatchblacklist": "Password policy that enforces that passwords are not on a list of blacklisted passwords (often previously used during MediaWiki automated testing)", "passwordpolicies-policy-maximalpasswordlength": "Password policy that enforces a maximum number of characters a password must be. $1 - maximum number of characters that a password can be", "passwordpolicies-policy-passwordcannotbepopular": "Password policy that enforces that a password is not in a list of $1 number of \"popular\" passwords. $1 - number of popular passwords the password will be checked against", - "easydeflate-invaliddeflate": "Error message if the content passed to easydeflate was not deflated (compressed) properly" + "easydeflate-invaliddeflate": "Error message if the content passed to easydeflate was not deflated (compressed) properly", + "unprotected-js": "Error message shown when trying to load javascript via action=raw that is not protected" } -- 2.20.1