diff options
author | sbassett <sbassett@wikimedia.org> | 2019-04-16 17:09:43 -0500 |
---|---|---|
committer | SBassett <sbassett@wikimedia.org> | 2019-04-24 15:38:40 +0000 |
commit | d965b0b4652b566b1f53be756c13190b958dd7fa (patch) | |
tree | de99e7b22a38d0739ad3686a77b4b4d1de4f2f83 /includes | |
parent | b6e3d8df08516906287015c6d826f36d47d85fe2 (diff) | |
download | mediawikicore-d965b0b4652b566b1f53be756c13190b958dd7fa.tar.gz mediawikicore-d965b0b4652b566b1f53be756c13190b958dd7fa.zip |
[SECURITY] [API BREAKING CHANGE] Require logout token.
Special:Userlogout now requires a token
Api action=logout requires a csrf token and the request to be POSTed
Patch author: bawolff
Bug: T25227
Change-Id: Icb674095956bb3f6c847c9553c53e404402ea774
Diffstat (limited to 'includes')
-rw-r--r-- | includes/api/ApiLogout.php | 10 | ||||
-rw-r--r-- | includes/skins/SkinTemplate.php | 15 | ||||
-rw-r--r-- | includes/specials/SpecialUserLogout.php | 22 |
3 files changed, 40 insertions, 7 deletions
diff --git a/includes/api/ApiLogout.php b/includes/api/ApiLogout.php index c663d1e4bb23..39a96ac56308 100644 --- a/includes/api/ApiLogout.php +++ b/includes/api/ApiLogout.php @@ -59,13 +59,21 @@ class ApiLogout extends ApiBase { Hooks::run( 'UserLogoutComplete', [ &$user, &$injected_html, $oldName ] ); } + public function mustBePosted() { + return true; + } + + public function needsToken() { + return 'csrf'; + } + public function isReadMode() { return false; } protected function getExamplesMessages() { return [ - 'action=logout' + 'action=logout&token=123ABC' => 'apihelp-logout-example-logout', ]; } diff --git a/includes/skins/SkinTemplate.php b/includes/skins/SkinTemplate.php index 8f45f281c231..25771bc95245 100644 --- a/includes/skins/SkinTemplate.php +++ b/includes/skins/SkinTemplate.php @@ -617,16 +617,18 @@ class SkinTemplate extends Skin { $page = Title::newFromText( $request->getVal( 'title', '' ) ); } $page = $request->getVal( 'returnto', $page ); - $a = []; + $returnto = []; if ( strval( $page ) !== '' ) { - $a['returnto'] = $page; + $returnto['returnto'] = $page; $query = $request->getVal( 'returntoquery', $this->thisquery ); + $paramsArray = wfCgiToArray( $query ); + unset( $paramsArray['logoutToken'] ); + $query = wfArrayToCgi( $paramsArray ); if ( $query != '' ) { - $a['returntoquery'] = $query; + $returnto['returntoquery'] = $query; } } - $returnto = wfArrayToCgi( $a ); if ( $this->loggedin ) { $personal_urls['userpage'] = [ 'text' => $this->username, @@ -691,9 +693,10 @@ class SkinTemplate extends Skin { $personal_urls['logout'] = [ 'text' => $this->msg( 'pt-userlogout' )->text(), 'href' => self::makeSpecialUrl( 'Userlogout', - // userlogout link must always contain an & character, otherwise we might not be able + // Note: userlogout link must always contain an & character, otherwise we might not be able // to detect a buggy precaching proxy (T19790) - $title->isSpecial( 'Preferences' ) ? 'noreturnto' : $returnto ), + ( $title->isSpecial( 'Preferences' ) ? [] : $returnto ) + + [ 'logoutToken' => $this->getUser()->getEditToken( 'logoutToken', $this->getRequest() ) ] ), 'active' => false ]; } diff --git a/includes/specials/SpecialUserLogout.php b/includes/specials/SpecialUserLogout.php index a9b732efb120..568327d25b23 100644 --- a/includes/specials/SpecialUserLogout.php +++ b/includes/specials/SpecialUserLogout.php @@ -48,6 +48,28 @@ class SpecialUserLogout extends UnlistedSpecialPage { $this->setHeaders(); $this->outputHeader(); + $out = $this->getOutput(); + $user = $this->getUser(); + $request = $this->getRequest(); + + $logoutToken = $request->getVal( 'logoutToken' ); + $urlParams = [ + 'logoutToken' => $user->getEditToken( 'logoutToken', $request ) + ] + $request->getValues(); + unset( $urlParams['title'] ); + $continueLink = $this->getFullTitle()->getFullUrl( $urlParams ); + + if ( $logoutToken === null ) { + $this->getOutput()->addWikiMsg( 'userlogout-continue', $continueLink ); + return; + } + if ( !$this->getUser()->matchEditToken( + $logoutToken, 'logoutToken', $this->getRequest(), 24 * 60 * 60 + ) ) { + $this->getOutput()->addWikiMsg( 'userlogout-sessionerror', $continueLink ); + return; + } + // Make sure it's possible to log out $session = MediaWiki\Session\SessionManager::getGlobalSession(); if ( !$session->canSetUser() ) { |