diff options
author | Reedy <reedy@wikimedia.org> | 2012-03-22 22:14:10 +0000 |
---|---|---|
committer | Reedy <reedy@wikimedia.org> | 2012-03-22 22:14:10 +0000 |
commit | 34cd6b23ff2115232dd66ef9b8404c30767a570d (patch) | |
tree | b6d7a294398244a363a90b5598800ebba03009a8 /includes/resourceloader | |
parent | 39db773837c064c558bf489f64247b18d3949a89 (diff) | |
download | mediawikicore-1.19.0beta2.tar.gz mediawikicore-1.19.0beta2.zip |
* (bug 34212) ApiBlock/ApiUnblock allow action to take place without a token parameter present1.19.0beta2
* (bug 35317) CSRF in Special:Upload
Revert r56793, which removed the CSRF check for Special:Upload for normal file
uploads. Cross-site posting of file uploads without user interaction has been
possible since at least as early as Chrome 8 (late 2010) and Firefox 6 (mid
2011).
Commonist has used api.php since version 0.4.0 (April 2010), and the API
already requires an edit token, so Commonist 0.4.0+ is not affected by this
change.
* (bug 34907) Fix for CSRF vulnerability due to mw.user.tokens. Patch by Roan
Kattouw and Tim Starling.
* Filter out private modules early in ResourceLoader::makeResponse() and just
pretend they weren't specified. This means these modules cannot be loaded
through load.php . This filtering must not happen in makeModuleResponse(),
because that would break inlining.
* Force inlining of private modules in OutputPage::makeResourceLoaderLink(),
disregarding $wgResourceLoaderInlinePrivateModules
* Remove $wgResourceLoaderInlinePrivateModules
* Remove special treatment of private modules ($private) in
ResourceLoader::makeResponse() and sendResponseHeaders(), because we're not
allowing private modules to be loaded through here any more
* Remove identity checks in ResourceLoaderUserOptionsModule and
ResourceLoaderUserCSSPrefsModule, they didn't make a lot of sense before but
they're certainly useless now.
* Factored out error comment construction in ResourceLoader.php and stripped
comment terminations from exception messages. I didn't find an XSS
vulnerability but it looked scary.
Change-Id: I0a4d7d2cc19ab3af018604037be150bda5187434
Diffstat (limited to 'includes/resourceloader')
-rw-r--r-- | includes/resourceloader/ResourceLoader.php | 51 | ||||
-rw-r--r-- | includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php | 29 | ||||
-rw-r--r-- | includes/resourceloader/ResourceLoaderUserOptionsModule.php | 30 |
3 files changed, 33 insertions, 77 deletions
diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index 55fbddc401b2..9175b10de27b 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -173,7 +173,7 @@ class ResourceLoader { $cache->set( $key, $result ); } catch ( Exception $exception ) { // Return exception as a comment - $result = "/*\n{$exception->__toString()}\n*/\n"; + $result = $this->makeComment( $exception->__toString() ); } wfProfileOut( __METHOD__ ); @@ -430,13 +430,20 @@ class ResourceLoader { ob_start(); wfProfileIn( __METHOD__ ); - $exceptions = ''; + $errors = ''; // Split requested modules into two groups, modules and missing $modules = array(); $missing = array(); foreach ( $context->getModules() as $name ) { if ( isset( $this->moduleInfos[$name] ) ) { + $module = $this->getModule( $name ); + // Do not allow private modules to be loaded from the web. + // This is a security issue, see bug 34907. + if ( $module->getGroup() === 'private' ) { + $errors .= $this->makeComment( "Cannot show private module \"$name\"" ); + continue; + } $modules[$name] = $this->getModule( $name ); } else { $missing[] = $name; @@ -448,12 +455,11 @@ class ResourceLoader { $this->preloadModuleInfo( array_keys( $modules ), $context ); } catch( Exception $e ) { // Add exception to the output as a comment - $exceptions .= "/*\n{$e->__toString()}\n*/\n"; + $errors .= $this->makeComment( $e->__toString() ); } wfProfileIn( __METHOD__.'-getModifiedTime' ); - $private = false; // To send Last-Modified and support If-Modified-Since, we need to detect // the last modified time $mtime = wfTimestamp( TS_UNIX, $wgCacheEpoch ); @@ -462,22 +468,18 @@ class ResourceLoader { * @var $module ResourceLoaderModule */ try { - // Bypass Squid and other shared caches if the request includes any private modules - if ( $module->getGroup() === 'private' ) { - $private = true; - } // Calculate maximum modified time $mtime = max( $mtime, $module->getModifiedTime( $context ) ); } catch ( Exception $e ) { // Add exception to the output as a comment - $exceptions .= "/*\n{$e->__toString()}\n*/\n"; + $errors .= $this->makeComment( $e->__toString() ); } } wfProfileOut( __METHOD__.'-getModifiedTime' ); // Send content type and cache related headers - $this->sendResponseHeaders( $context, $mtime, $private ); + $this->sendResponseHeaders( $context, $mtime ); // If there's an If-Modified-Since header, respond with a 304 appropriately if ( $this->tryRespondLastModified( $context, $mtime ) ) { @@ -489,20 +491,20 @@ class ResourceLoader { $response = $this->makeModuleResponse( $context, $modules, $missing ); // Prepend comments indicating exceptions - $response = $exceptions . $response; + $response = $errors . $response; // Capture any PHP warnings from the output buffer and append them to the // response in a comment if we're in debug mode. if ( $context->getDebug() && strlen( $warnings = ob_get_contents() ) ) { - $response = "/*\n$warnings\n*/\n" . $response; + $response = $this->makeComment( $warnings ) . $response; } // Remove the output buffer and output the response ob_end_clean(); echo $response; - // Save response to file cache unless there are private modules or errors - if ( isset( $fileCache ) && !$private && !$exceptions && !$missing ) { + // Save response to file cache unless there are errors + if ( isset( $fileCache ) && !$errors && !$missing ) { // Cache single modules...and other requests if there are enough hits if ( ResourceFileCache::useFileCache( $context ) ) { if ( $fileCache->isCacheWorthy() ) { @@ -520,10 +522,9 @@ class ResourceLoader { * Send content type and last modified headers to the client. * @param $context ResourceLoaderContext * @param $mtime string TS_MW timestamp to use for last-modified - * @param $private bool True iff response contains any private modules * @return void */ - protected function sendResponseHeaders( ResourceLoaderContext $context, $mtime, $private ) { + protected function sendResponseHeaders( ResourceLoaderContext $context, $mtime ) { global $wgResourceLoaderMaxage; // If a version wasn't specified we need a shorter expiry time for updates // to propagate to clients quickly @@ -547,13 +548,8 @@ class ResourceLoader { header( 'Cache-Control: private, no-cache, must-revalidate' ); header( 'Pragma: no-cache' ); } else { - if ( $private ) { - header( "Cache-Control: private, max-age=$maxage" ); - $exp = $maxage; - } else { - header( "Cache-Control: public, max-age=$maxage, s-maxage=$smaxage" ); - $exp = min( $maxage, $smaxage ); - } + header( "Cache-Control: public, max-age=$maxage, s-maxage=$smaxage" ); + $exp = min( $maxage, $smaxage ); header( 'Expires: ' . wfTimestamp( TS_RFC2822, $exp + time() ) ); } } @@ -650,6 +646,11 @@ class ResourceLoader { return false; // cache miss } + protected function makeComment( $text ) { + $encText = str_replace( '*/', '* /', $text ); + return "/*\n$encText\n*/\n"; + } + /** * Generates code for a response * @@ -674,7 +675,7 @@ class ResourceLoader { $blobs = MessageBlobStore::get( $this, $modules, $context->getLanguage() ); } catch ( Exception $e ) { // Add exception to the output as a comment - $exceptions .= "/*\n{$e->__toString()}\n*/\n"; + $exceptions .= $this->makeComment( $e->__toString() ); } } else { $blobs = array(); @@ -753,7 +754,7 @@ class ResourceLoader { } } catch ( Exception $e ) { // Add exception to the output as a comment - $exceptions .= "/*\n{$e->__toString()}\n*/\n"; + $exceptions .= $this->makeComment( $e->__toString() ); // Register module as missing $missing[] = $name; diff --git a/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php b/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php index b5a24354e019..02693d3ec9b3 100644 --- a/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php +++ b/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php @@ -44,30 +44,7 @@ class ResourceLoaderUserCSSPrefsModule extends ResourceLoaderModule { } global $wgUser; - - if ( $context->getUser() === $wgUser->getName() ) { - return $this->modifiedTime[$hash] = wfTimestamp( TS_UNIX, $wgUser->getTouched() ); - } else { - return 1; - } - } - - /** - * Fetch the context's user options, or if it doesn't match current user, - * the default options. - * - * @param $context ResourceLoaderContext: Context object - * @return Array: List of user options keyed by option name - */ - protected function contextUserOptions( ResourceLoaderContext $context ) { - global $wgUser; - - // Verify identity -- this is a private module - if ( $context->getUser() === $wgUser->getName() ) { - return $wgUser->getOptions(); - } else { - return User::getDefaultOptions(); - } + return $this->modifiedTime[$hash] = wfTimestamp( TS_UNIX, $wgUser->getTouched() ); } /** @@ -75,10 +52,10 @@ class ResourceLoaderUserCSSPrefsModule extends ResourceLoaderModule { * @return array */ public function getStyles( ResourceLoaderContext $context ) { - global $wgAllowUserCssPrefs; + global $wgAllowUserCssPrefs, $wgUser; if ( $wgAllowUserCssPrefs ) { - $options = $this->contextUserOptions( $context ); + $options = $wgUser->getOptions(); // Build CSS rules $rules = array(); diff --git a/includes/resourceloader/ResourceLoaderUserOptionsModule.php b/includes/resourceloader/ResourceLoaderUserOptionsModule.php index 84932adddf8c..7b1622053563 100644 --- a/includes/resourceloader/ResourceLoaderUserOptionsModule.php +++ b/includes/resourceloader/ResourceLoaderUserOptionsModule.php @@ -42,32 +42,9 @@ class ResourceLoaderUserOptionsModule extends ResourceLoaderModule { if ( isset( $this->modifiedTime[$hash] ) ) { return $this->modifiedTime[$hash]; } - + global $wgUser; - - if ( $context->getUser() === $wgUser->getName() ) { - return $this->modifiedTime[$hash] = wfTimestamp( TS_UNIX, $wgUser->getTouched() ); - } else { - return 1; - } - } - - /** - * Fetch the context's user options, or if it doesn't match current user, - * the default options. - * - * @param $context ResourceLoaderContext: Context object - * @return Array: List of user options keyed by option name - */ - protected function contextUserOptions( ResourceLoaderContext $context ) { - global $wgUser; - - // Verify identity -- this is a private module - if ( $context->getUser() === $wgUser->getName() ) { - return $wgUser->getOptions(); - } else { - return User::getDefaultOptions(); - } + return $this->modifiedTime[$hash] = wfTimestamp( TS_UNIX, $wgUser->getTouched() ); } /** @@ -75,8 +52,9 @@ class ResourceLoaderUserOptionsModule extends ResourceLoaderModule { * @return string */ public function getScript( ResourceLoaderContext $context ) { + global $wgUser; return Xml::encodeJsCall( 'mw.user.options.set', - array( $this->contextUserOptions( $context ) ) ); + array( $wgUser->getOptions() ) ); } /** |