SECURITY: Don't allow loading unprotected JS files
authorBrian Wolff <bawolff+wn@gmail.com>
Thu, 27 Sep 2018 11:42:37 +0000 (11:42 +0000)
committerPaladox <thomasmulhall410@yahoo.com>
Sun, 21 Oct 2018 18:09:44 +0000 (19:09 +0100)
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

RELEASE-NOTES-1.31
includes/actions/RawAction.php
languages/i18n/en.json
languages/i18n/qqq.json

index 3e7f5d1..6421a04 100644 (file)
@@ -18,6 +18,8 @@ THIS IS NOT A RELEASE YET
 * (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.
 * (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.
+* (T113042) Do not allow loading pages raw with a text/javascript MIME type if
+  non-admins can edit the page.
 
 == MediaWiki 1.31.1 ==
 
 
 == MediaWiki 1.31.1 ==
 
index 159e708..3fda401 100644 (file)
@@ -123,6 +123,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();
                $response->header( 'Content-type: ' . $contentType . '; charset=UTF-8' );
 
                $text = $this->getRawText();
index 89564e0..31adb7b 100644 (file)
        "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-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.",
-       "unregistered-user-config": "For security reasons JavaScript, CSS and JSON user subpages cannot be loaded for unregistered users."
+       "unregistered-user-config": "For security reasons JavaScript, CSS and JSON user subpages cannot be loaded for unregistered users.",
+       "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"
 }
 }
index 8e8372b..6348926 100644 (file)
        "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-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",
-       "unregistered-user-config": "Shown when viewing a user JS, CSS or JSON subpage with ?action=raw&ctype=<mime type> where there is no such user. It is shown as a paragraph after a header saying 'Forbidden'."
+       "unregistered-user-config": "Shown when viewing a user JS, CSS or JSON subpage with ?action=raw&ctype=<mime type> where there is no such user. It is shown as a paragraph after a header saying 'Forbidden'.",
+       "unprotected-js": "Error message shown when trying to load javascript via action=raw that is not protected"
 }
 }