From 90232b6f36ee5a1473f2e865cc7a72d0014db4c7 Mon Sep 17 00:00:00 2001 From: Brian Wolff Date: Tue, 15 May 2018 00:34:14 +0000 Subject: [PATCH] SECURITY: Disallow loading JS/CSS/Json subpages from unregistered users and log Loading JS from an unregistered user's JS subpage is a severe security risk as someone could potentially register that account and then modify the JS. Bug: T207603 Change-Id: I741736e12b0ed49e95f22c869a2b53e2c97b31f0 --- RELEASE-NOTES-1.31 | 2 ++ includes/actions/RawAction.php | 30 +++++++++++++++++++++++++++++- languages/i18n/en.json | 3 ++- languages/i18n/qqq.json | 3 ++- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/RELEASE-NOTES-1.31 b/RELEASE-NOTES-1.31 index 2245aba9e8..3e7f5d1534 100644 --- a/RELEASE-NOTES-1.31 +++ b/RELEASE-NOTES-1.31 @@ -16,6 +16,8 @@ THIS IS NOT A RELEASE YET * Fix PHP 7.3 warnings "preg_replace(): [...] invalid range in character class" * (T207540) Include IP address in "Login for $1 succeeded" log entry. * (T207541) Pass email address to mail(). +* (T207603) User JS may no longer be loaded with mime type text/javascript if + there is no account associated with the username. == MediaWiki 1.31.1 == diff --git a/includes/actions/RawAction.php b/includes/actions/RawAction.php index 812f9623ff..159e7081a4 100644 --- a/includes/actions/RawAction.php +++ b/includes/actions/RawAction.php @@ -26,6 +26,8 @@ * @file */ +use MediaWiki\Logger\LoggerFactory; + /** * A simple method to retrieve the plain source of an article, * using "action=raw" in the GET request string. @@ -85,7 +87,6 @@ class RawAction extends FormlessAction { $response->header( $this->getOutput()->getKeyHeader() ); } - $response->header( 'Content-type: ' . $contentType . '; charset=UTF-8' ); // Output may contain user-specific data; // vary generated content for open sessions on private wikis $privateCache = !User::isEveryoneAllowed( 'read' ) && @@ -97,6 +98,33 @@ class RawAction extends FormlessAction { 'Cache-Control: ' . $mode . ', s-maxage=' . $smaxage . ', max-age=' . $maxage ); + // In the event of user JS, don't allow loading a user JS/CSS/Json + // subpage that has no registered user associated with, as + // someone could register the account and take control of the + // JS/CSS/Json page. + $title = $this->getTitle(); + if ( $title->isUserConfigPage() && $contentType !== 'text/x-wiki' ) { + // not using getRootText() as we want this to work + // even if subpages are disabled. + $rootPage = strtok( $title->getText(), '/' ); + $userFromTitle = User::newFromName( $rootPage, 'usable' ); + if ( !$userFromTitle || $userFromTitle->getId() === 0 ) { + $log = LoggerFactory::getInstance( "security" ); + $log->warning( + "Unsafe JS/CSS/Json load - {user} loaded {title} with {ctype}", + [ + 'user' => $this->getUser()->getName(), + 'title' => $title->getPrefixedDBKey(), + 'ctype' => $contentType, + ] + ); + $msg = wfMessage( 'unregistered-user-config' ); + throw new HttpError( 403, $msg ); + } + } + + $response->header( 'Content-type: ' . $contentType . '; charset=UTF-8' ); + $text = $this->getRawText(); // Don't return a 404 response for CSS or JavaScript; diff --git a/languages/i18n/en.json b/languages/i18n/en.json index 7374f38ce1..89564e05a0 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -4467,5 +4467,6 @@ "pagedata-title": "Page data", "pagedata-text": "This page provides a data interface to pages. Please provide the page title in the URL, using subpage syntax.\n* Content negotiation applies based on your client's Accept header. This means that the page data will be provided in the format preferred by your client.", "pagedata-not-acceptable": "No matching format found. Supported MIME types: $1", - "pagedata-bad-title": "Invalid title: $1." + "pagedata-bad-title": "Invalid title: $1.", + "unregistered-user-config": "For security reasons JavaScript, CSS and JSON user subpages cannot be loaded for unregistered users." } diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index 760d37dd1f..8e8372bb75 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -4664,5 +4664,6 @@ "pagedata-title": "Title shown on the special page when a form or text is presented", "pagedata-text": "Error shown when none of the formats acceptable to the client is supported (HTTP error 406). Parameters:\n* $1 - the list of supported MIME types", "pagedata-not-acceptable": "No matching format found. Supported MIME types: $1", - "pagedata-bad-title": "Error shown when the requested title is invalid. Parameters:\n* $1: the malformed ID" + "pagedata-bad-title": "Error shown when the requested title is invalid. Parameters:\n* $1: the malformed ID", + "unregistered-user-config": "Shown when viewing a user JS, CSS or JSON subpage with ?action=raw&ctype= where there is no such user. It is shown as a paragraph after a header saying 'Forbidden'." } -- 2.20.1