r7360 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r7359‎ | r7360 | r7361 >
Date:06:21, 4 February 2005
Author:vibber
Status:old
Tags:
Comment:
Bump to 1.3.10. Security tweaks:
* Leave user CSS/JS off by default
* Tighten user CSS/JS preview activation
* Require logged-in edits to include an extra session credential
* ogg removed from default upload whitelist
Modified paths:
  • /branches/REL1_3/phase3/RELEASE-NOTES (modified) (history)
  • /branches/REL1_3/phase3/includes/DefaultSettings.php (modified) (history)
  • /branches/REL1_3/phase3/includes/EditPage.php (modified) (history)
  • /branches/REL1_3/phase3/includes/Skin.php (modified) (history)
  • /branches/REL1_3/phase3/includes/SkinPHPTal.php (modified) (history)
  • /branches/REL1_3/phase3/includes/User.php (modified) (history)

Diff [purge]

Index: branches/REL1_3/phase3/includes/User.php
@@ -738,6 +738,39 @@
739739 }
740740 return false;
741741 }
 742+
 743+ /**
 744+ * Initialize (if necessary) and return a session token value
 745+ * which can be used in edit forms to show that the user's
 746+ * login credentials aren't being hijacked with a foreign form
 747+ * submission.
 748+ *
 749+ * @return string
 750+ * @access public
 751+ */
 752+ function editToken() {
 753+ if( !isset( $_SESSION['wsEditToken'] ) ) {
 754+ $token = dechex( mt_rand() ) . dechex( mt_rand() );
 755+ $_SESSION['wsEditToken'] = $token;
 756+ }
 757+ return $_SESSION['wsEditToken'];
 758+ }
 759+
 760+ /**
 761+ * Check given value against the token value stored in the session.
 762+ * A match should confirm that the form was submitted from the
 763+ * user's own login session, not a form submission from a third-party
 764+ * site.
 765+ *
 766+ * @param string $val
 767+ * @return bool
 768+ * @access public
 769+ */
 770+ function matchEditToken( $val ) {
 771+ if( !isset( $_SESSION['wsEditToken'] ) )
 772+ return false;
 773+ return $_SESSION['wsEditToken'] == $val;
 774+ }
742775 }
743776
744777 ?>
Index: branches/REL1_3/phase3/includes/DefaultSettings.php
@@ -9,7 +9,7 @@
1010 # like $wgScriptPath, you must also localize everything that
1111 # depends on it.
1212
13 -$wgVersion = '1.3.9';
 13+$wgVersion = '1.3.10';
1414
1515 $wgSitename = 'MediaWiki'; # Please customize!
1616 $wgMetaNamespace = FALSE; # will be same as you set $wgSitename
@@ -315,7 +315,7 @@
316316
317317 # This is the list of preferred extensions for uploading files. Uploading
318318 # files with extensions not in this list will trigger a warning.
319 -$wgFileExtensions = array( 'png', 'gif', 'jpg', 'jpeg', 'ogg' );
 319+$wgFileExtensions = array( 'png', 'gif', 'jpg', 'jpeg' );
320320
321321 # Files with these extensions will never be allowed as uploads.
322322 $wgFileBlacklist = array(
@@ -474,10 +474,14 @@
475475 $wgExtensionFunctions = array();
476476
477477 # Allow user Javascript page?
478 -$wgAllowUserJs = true;
 478+# This enables a lot of neat customizations, but may
 479+# increase security risk to users and server load.
 480+$wgAllowUserJs = false;
479481
480482 # Allow user Cascading Style Sheets (CSS)?
481 -$wgAllowUserCss = true;
 483+# This enables a lot of neat customizations, but may
 484+# increase security risk to users and server load.
 485+$wgAllowUserCss = false;
482486
483487 # Filter for Special:Randompage. Part of a WHERE clause
484488 $wgExtraRandompageSQL = false;
Index: branches/REL1_3/phase3/includes/SkinPHPTal.php
@@ -531,12 +531,13 @@
532532 }
533533 /* private */ function setupUserCssJs () {
534534 global $wgRequest, $wgTitle;
 535+ global $wgAllowUserCss, $wgAllowUserJs;
535536 $action = $wgRequest->getText('action');
536537 # generated css
537538 $this->usercss = '@import "'.$this->makeUrl('-','action=raw&gen=css').'";'."\n";
538539
539 - if( $this->loggedin ) {
540 - if($wgTitle->isCssSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) {
 540+ if( $this->loggedin && $wgAllowUserCss ) {
 541+ if( $wgTitle->isCssSubpage() and $this->userCanPreview( $action ) ) {
541542 # generated css
542543 $this->usercss = '@import "'.$this->makeUrl('-','action=raw&smaxage=0&maxage=0&gen=css').'";'."\n";
543544 // css preview
@@ -548,7 +549,9 @@
549550 $this->usercss .= '@import "'.
550551 $this->makeUrl($this->userpage.'/'.$this->skinname.'.css', 'action=raw&ctype=text/css').'";'."\n";
551552 }
552 - if($wgTitle->isJsSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) {
 553+ }
 554+ if( $this->loggedin && $wgAllowUserJs ) {
 555+ if( $wgTitle->isJsSubpage() and $this->userCanPreview( $action ) ) {
553556 # XXX: additional security check/prompt?
554557 $this->userjsprev = $wgRequest->getText('wpTextbox1');
555558 } else {
Index: branches/REL1_3/phase3/includes/Skin.php
@@ -166,6 +166,30 @@
167167 return $r;
168168 }
169169
 170+ /**
 171+ * To make it harder for someone to slip a user a fake
 172+ * user-JavaScript or user-CSS preview, a random token
 173+ * is associated with the login session. If it's not
 174+ * passed back with the preview request, we won't render
 175+ * the code.
 176+ *
 177+ * @param string $action
 178+ * @return bool
 179+ * @access private
 180+ */
 181+ function userCanPreview( $action ) {
 182+ global $wgTitle, $wgRequest, $wgUser;
 183+
 184+ if( $action != 'submit' )
 185+ return false;
 186+ if( !$wgRequest->wasPosted() )
 187+ return false;
 188+ if( !$wgTitle->userCanEditCssJsSubpage() )
 189+ return false;
 190+ return $wgUser->matchEditToken(
 191+ $wgRequest->getVal( 'wpEditToken' ) );
 192+ }
 193+
170194 # get the user/site-specific stylesheet, SkinPHPTal called from RawPage.php (settings are cached that way)
171195 function getUserStylesheet() {
172196 global $wgOut, $wgStylePath, $wgLang, $wgUser, $wgRequest, $wgTitle, $wgAllowUserCss;
@@ -174,7 +198,7 @@
175199 $s = "@import \"$wgStylePath/$sheet\";\n";
176200 if($wgLang->isRTL()) $s .= "@import \"$wgStylePath/common_rtl.css\";\n";
177201 if( $wgAllowUserCss && $wgUser->getID() != 0 ) { # logged in
178 - if($wgTitle->isCssSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) {
 202+ if($wgTitle->isCssSubpage() && $this->userCanPreview( $action ) ) {
179203 $s .= $wgRequest->getText('wpTextbox1');
180204 } else {
181205 $userpage = $wgLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
Index: branches/REL1_3/phase3/includes/EditPage.php
@@ -73,7 +73,14 @@
7474 if( !preg_match( '/^\d{14}$/', $this->edittime )) $this->edittime = "";
7575
7676 $this->preview = $request->getCheck( 'wpPreview' );
77 - $this->save = $request->wasPosted() && !$this->preview;
 77+ if( $this->tokenOk( $request ) ) {
 78+ $this->save = $request->wasPosted() && !$this->preview;
 79+ } else {
 80+ # Page might be a hack attempt posted from
 81+ # an external site. Preview instead of saving.
 82+ $this->save = false;
 83+ $this->preview = $request->wasPosted();
 84+ }
7885 $this->minoredit = $request->getCheck( 'wpMinoredit' );
7986 $this->watchthis = $request->getCheck( 'wpWatchthis' );
8087
@@ -83,6 +90,24 @@
8491 $this->section = $request->getVal( 'wpSection', $request->getVal( 'section' ) );
8592 }
8693
 94+ /**
 95+ * Make sure the form isn't faking a user's credentials.
 96+ *
 97+ * @param WebRequest $request
 98+ * @return bool
 99+ * @access private
 100+ */
 101+ function tokenOk( &$request ) {
 102+ global $wgUser;
 103+ if( $wgUser->getId() == 0 ) {
 104+ # Anonymous users may not have a session
 105+ # open. Don't tokenize.
 106+ return true;
 107+ } else {
 108+ return $wgUser->matchEditToken( $request->getVal( 'wpEditToken' ) );
 109+ }
 110+ }
 111+
87112 # Since there is only one text field on the edit form,
88113 # pressing <enter> will cause the form to be submitted, but
89114 # the submit button value won't appear in the query, so we
@@ -235,6 +260,20 @@
236261 # Enabled article-related sidebar, toplinks, etc.
237262 $wgOut->setArticleRelated( true );
238263
 264+ if ( 0 != $wgUser->getID() ) {
 265+ /**
 266+ * To make it harder for someone to slip a user a page
 267+ * which submits an edit form to the wiki without their
 268+ * knowledge, a random token is associated with the login
 269+ * session. If it's not passed back with the submission,
 270+ * we won't save the page, or render user JavaScript and
 271+ * CSS previews.
 272+ */
 273+ $token = htmlspecialchars( $wgUser->editToken() );
 274+ $wgOut->addHTML( "
 275+<input type='hidden' value=\"$token\" name=\"wpEditToken\" />\n" );
 276+ }
 277+
239278 if ( $isConflict ) {
240279 $s = wfMsg( "editconflict", $this->mTitle->getPrefixedText() );
241280 $wgOut->setPageTitle( $s );
@@ -441,6 +480,20 @@
442481 <input type='hidden' value=\"" . htmlspecialchars( $this->section ) . "\" name=\"wpSection\" />
443482 <input type='hidden' value=\"{$this->edittime}\" name=\"wpEdittime\" />\n" );
444483
 484+ if ( 0 != $wgUser->getID() ) {
 485+ /**
 486+ * To make it harder for someone to slip a user a page
 487+ * which submits an edit form to the wiki without their
 488+ * knowledge, a random token is associated with the login
 489+ * session. If it's not passed back with the submission,
 490+ * we won't save the page, or render user JavaScript and
 491+ * CSS previews.
 492+ */
 493+ $token = htmlspecialchars( $wgUser->editToken() );
 494+ $wgOut->addHTML( "
 495+<input type='hidden' value=\"$token\" name=\"wpEditToken\" />\n" );
 496+ }
 497+
445498 if ( $isConflict ) {
446499 $wgOut->addHTML( "<h2>" . wfMsg( "yourdiff" ) . "</h2>\n" );
447500 DifferenceEngine::showDiff( $this->textbox2, $this->textbox1,
Index: branches/REL1_3/phase3/RELEASE-NOTES
@@ -3,6 +3,34 @@
44 Security reminder: MediaWiki does not require PHP's register_globals
55 setting since version 1.2.0. If you have it on, turn it *off* if you can.
66
 7+== Version 1.3.10, 2005-02-03 ==
 8+
 9+MediaWiki 1.3.10 is a security release.
 10+
 11+An attacker could craft a URL which, when visited by a particular
 12+logged-in user, would execute arbitrary JavaScript code on the user's
 13+browser in the wiki's site context. This attack has been blocked, and as
 14+an extra precaution the user CSS and JavaScript subpage support is now
 15+disabled by default. Sites which want this ability may set $wgAllowUserCss
 16+and $wgAllowUserJs in LocalSettings.php.
 17+
 18+Additional protections have been added against off-site form submissions
 19+hijacking user credentials. Authors of bot tools may need to update their
 20+code to include additional fields.
 21+
 22+All wikis running 1.3.x are strongly urged to upgrade to 1.3.10.
 23+
 24+Changes from 1.3.9:
 25+* Logged-in edits and preview of user CSS/JS are now locked to a session token.
 26+* Per-user CSS and JavaScript subpage customizations now disabled by default.
 27+ They can be re-enabled via $wgAllowUserJs and $wgAllowUserCss.
 28+* Removed .ogg from the default uploads whitelist as an extra precaution.
 29+ If your web server is configured to serve Ogg files with the correct
 30+ Content-Type header, you can re-add it in LocalSettings.php:
 31+ $wgFileExtensions[] = 'ogg';
 32+
 33+
 34+
735 == Version 1.3.9, 2004-12-12 ==
836
937 MediaWiki 1.3.9 is a security and bug fix release.

Status & tagging log