From: csteipp Date: Mon, 5 Oct 2015 23:58:42 +0000 (-0700) Subject: SECURITY: Make Special:MyPage and friends fake redirect to prevent info leak X-Git-Tag: 1.31.0-rc.0~8633 X-Git-Url: https://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/comptes/ajouter.php?a=commitdiff_plain;h=1461ff2ecfef40caef35a5d91cfb5849631564ee;p=lhc%2Fweb%2Fwiklou.git SECURITY: Make Special:MyPage and friends fake redirect to prevent info leak This prevents a malicious person from using external resources on their website to cause the victim's web browser to load Special:MyPage -> User:Username, and then looking it up in the page hit statistics in order to correlate IPs from the malicious person's server log, with usernames on wiki. This feature can be disabled with $wgHideIdentifiableRedirects. Bug: T109724 Signed-off-by: Chad Horohoe Change-Id: Ia0e742dc92c77af4832174dfa24c6dcaa6ee80e9 --- diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index f55cb56732..54216fdf52 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -4754,6 +4754,12 @@ $wgWhitelistReadRegexp = false; */ $wgEmailConfirmToEdit = false; +/** + * Should MediaWiki attempt to protect user's privacy when doing redirects? + * Keep this true if access counts to articles are made public. + */ +$wgHideIdentifiableRedirects = true; + /** * Permission keys given to users in each group. * diff --git a/includes/MediaWiki.php b/includes/MediaWiki.php index fe1bb8ec4d..19a0df7d5e 100644 --- a/includes/MediaWiki.php +++ b/includes/MediaWiki.php @@ -36,6 +36,11 @@ class MediaWiki { */ private $config; + /** + * @var String Cache what action this request is + */ + private $action; + /** * @param IContextSource|null $context */ @@ -141,13 +146,11 @@ class MediaWiki { * @return string Action */ public function getAction() { - static $action = null; - - if ( $action === null ) { - $action = Action::getActionName( $this->context ); + if ( $this->action === null ) { + $this->action = Action::getActionName( $this->context ); } - return $action; + return $this->action; } /** @@ -241,8 +244,37 @@ class MediaWiki { // Handle any other redirects. // Redirect loops, titleless URL, $wgUsePathInfo URLs, and URLs with a variant } elseif ( !$this->tryNormaliseRedirect( $title ) ) { + // Prevent information leak via Special:MyPage et al (T109724) + if ( $title->isSpecialPage() ) { + $specialPage = SpecialPageFactory::getPage( $title->getDBKey() ); + if ( $specialPage instanceof RedirectSpecialPage + && $this->config->get( 'HideIdentifiableRedirects' ) + && $specialPage->personallyIdentifiableTarget() + ) { + list( , $subpage ) = SpecialPageFactory::resolveAlias( $title->getDBKey() ); + $target = $specialPage->getRedirect( $subpage ); + // target can also be true. We let that case fall through to normal processing. + if ( $target instanceof Title ) { + $query = $specialPage->getRedirectQuery() ?: array(); + $request = new DerivativeRequest( $this->context->getRequest(), $query ); + $request->setRequestURL( $this->context->getRequest()->getRequestURL() ); + $this->context->setRequest( $request ); + // Do not varnish cache these. May vary even for anons + $this->context->getOutput()->lowerCdnMaxage( 0 ); + $this->context->setTitle( $target ); + $wgTitle = $target; + // Reset action type cache. (Special pages have only view) + $this->action = null; + $title = $target; + $output->addJsConfigVars( array( + 'wgInternalRedirectTargetUrl' => $target->getFullURL(), + ) ); + $output->addModules( 'mediawiki.action.view.redirect' ); + } + } + } - // Special pages + // Special pages ($title may have changed since if statement above) if ( NS_SPECIAL == $title->getNamespace() ) { // Actions that need to be made when we have a special pages SpecialPageFactory::executePath( $title, $this->context ); diff --git a/includes/specialpage/RedirectSpecialPage.php b/includes/specialpage/RedirectSpecialPage.php index 9129ee5d42..5047354e1a 100644 --- a/includes/specialpage/RedirectSpecialPage.php +++ b/includes/specialpage/RedirectSpecialPage.php @@ -94,6 +94,18 @@ abstract class RedirectSpecialPage extends UnlistedSpecialPage { ? $params : false; } + + /** + * Indicate if the target of this redirect can be used to identify + * a particular user of this wiki (e.g., if the redirect is to the + * user page of a User). See T109724. + * + * @since 1.27 + * @return bool + */ + public function personallyIdentifiableTarget() { + return false; + } } /** diff --git a/includes/specials/SpecialMyLanguage.php b/includes/specials/SpecialMyLanguage.php index 3d8ff97bb2..d11fbe638a 100644 --- a/includes/specials/SpecialMyLanguage.php +++ b/includes/specials/SpecialMyLanguage.php @@ -99,4 +99,15 @@ class SpecialMyLanguage extends RedirectSpecialArticle { return $base; } } + + /** + * Target can identify a specific user's language preference. + * + * @see T109724 + * @since 1.27 + * @return bool + */ + public function personallyIdentifiableTarget() { + return true; + } } diff --git a/includes/specials/SpecialMyRedirectPages.php b/includes/specials/SpecialMyRedirectPages.php index 5ef03f133d..850b1f635a 100644 --- a/includes/specials/SpecialMyRedirectPages.php +++ b/includes/specials/SpecialMyRedirectPages.php @@ -45,6 +45,16 @@ class SpecialMypage extends RedirectSpecialArticle { return Title::makeTitle( NS_USER, $this->getUser()->getName() . '/' . $subpage ); } + + /** + * Target identifies a specific User. See T109724. + * + * @since 1.27 + * @return bool + */ + public function personallyIdentifiableTarget() { + return true; + } } /** @@ -68,6 +78,16 @@ class SpecialMytalk extends RedirectSpecialArticle { return Title::makeTitle( NS_USER_TALK, $this->getUser()->getName() . '/' . $subpage ); } + + /** + * Target identifies a specific User. See T109724. + * + * @since 1.27 + * @return bool + */ + public function personallyIdentifiableTarget() { + return true; + } } /** @@ -90,6 +110,16 @@ class SpecialMycontributions extends RedirectSpecialPage { public function getRedirect( $subpage ) { return SpecialPage::getTitleFor( 'Contributions', $this->getUser()->getName() ); } + + /** + * Target identifies a specific User. See T109724. + * + * @since 1.27 + * @return bool + */ + public function personallyIdentifiableTarget() { + return true; + } } /** @@ -110,6 +140,16 @@ class SpecialMyuploads extends RedirectSpecialPage { public function getRedirect( $subpage ) { return SpecialPage::getTitleFor( 'Listfiles', $this->getUser()->getName() ); } + + /** + * Target identifies a specific User. See T109724. + * + * @since 1.27 + * @return bool + */ + public function personallyIdentifiableTarget() { + return true; + } } /** @@ -132,4 +172,14 @@ class SpecialAllMyUploads extends RedirectSpecialPage { return SpecialPage::getTitleFor( 'Listfiles', $this->getUser()->getName() ); } + + /** + * Target identifies a specific User. See T109724. + * + * @since 1.27 + * @return bool + */ + public function personallyIdentifiableTarget() { + return true; + } }