Disable user scripts on Special:Preferences, to prevent a compromised

script from being able to sniff passwords etc.

(The control flow here is hopelessly tangled between OutputPage and
the skins, and it doesn't help that Skin and SkinTemplate do things
differently for no particular reason.  I haven't made any attempt to
untangle it in this commit, but hopefully I at least haven't made it
too much worse.  Cleanup is welcome.)
This commit is contained in:
Ilmari Karonen 2007-05-08 20:48:02 +00:00
parent 360c62aca6
commit 183818b0a7
6 changed files with 20 additions and 10 deletions

View file

@ -40,6 +40,8 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
like [[User:#123|#123]]
* Use the standard HTTP fetch functions when retrieving remote wiki pages
through transwiki, so we can take advantage of cURL goodies if available
* Disable custom user javascript in Special:Preferences, to avoid the risk
of a compromised script sniffing passwords etc.
== Maintenance script changes since 1.10 ==

View file

@ -15,6 +15,7 @@ class OutputPage {
var $mLastModified, $mETag, $mCategoryLinks;
var $mScripts, $mLinkColours, $mPageLinkTitle;
var $mAllowUserJs;
var $mSuppressQuickbar;
var $mOnloadHandler;
var $mDoNothing;
@ -33,6 +34,8 @@ class OutputPage {
* Initialise private variables
*/
function __construct() {
global $wgAllowUserJs;
$this->mAllowUserJs = $wgAllowUserJs;
$this->mMetatags = $this->mKeywords = $this->mLinktags = array();
$this->mHTMLtitle = $this->mPagetitle = $this->mBodytext =
$this->mRedirect = $this->mLastModified =
@ -283,6 +286,9 @@ class OutputPage {
public function suppressQuickbar() { $this->mSuppressQuickbar = true; }
public function isQuickbarSuppressed() { return $this->mSuppressQuickbar; }
public function disallowUserJs() { $this->mAllowUserJs = false; }
public function isUserJsAllowed() { return $this->mAllowUserJs; }
public function addHTML( $text ) { $this->mBodytext .= $text; }
public function clearHTML() { $this->mBodytext = ''; }
public function getHTML() { return $this->mBodytext; }
@ -1138,7 +1144,7 @@ class OutputPage {
$ret .= "<link rel='stylesheet' type='text/css' $media href='$printsheet' />\n";
$sk = $wgUser->getSkin();
$ret .= $sk->getHeadScripts();
$ret .= $sk->getHeadScripts( $this->mAllowUserJs );
$ret .= $this->mScripts;
$ret .= $sk->getUserStyles();
$ret .= $this->getHeadItems();

View file

@ -334,8 +334,8 @@ class Skin extends Linker {
return self::makeVariablesScript( $vars );
}
function getHeadScripts() {
global $wgStylePath, $wgUser, $wgAllowUserJs, $wgJsMimeType, $wgStyleVersion;
function getHeadScripts( $allowUserJs ) {
global $wgStylePath, $wgUser, $wgJsMimeType, $wgStyleVersion;
$r = self::makeGlobalVariablesScript( array( 'skinname' => $this->getSkinName() ) );
@ -348,7 +348,7 @@ class Skin extends Linker {
$r .= "<script type=\"$wgJsMimeType\" src=\"".htmlspecialchars(self::makeUrl('-','action=raw&gen=js'))."\"><!-- site js --></script>\n";
}
}
if( $wgAllowUserJs && $wgUser->isLoggedIn() ) {
if( $allowUserJs && $wgUser->isLoggedIn() ) {
$userpage = $wgUser->getUserPage();
$userjs = htmlspecialchars( self::makeUrl(
$userpage->getPrefixedText().'/'.$this->getSkinName().'.js',

View file

@ -179,7 +179,7 @@ class SkinTemplate extends Skin {
$this->usercss = $this->userjs = $this->userjsprev = false;
$this->setupUserCss();
$this->setupUserJs();
$this->setupUserJs( $out->isUserJsAllowed() );
$this->titletxt = $this->mTitle->getPrefixedText();
wfProfileOut( "$fname-stuff" );
@ -984,14 +984,14 @@ class SkinTemplate extends Skin {
/**
* @private
*/
function setupUserJs() {
function setupUserJs( $allowUserJs ) {
$fname = 'SkinTemplate::setupUserJs';
wfProfileIn( $fname );
global $wgRequest, $wgAllowUserJs, $wgJsMimeType;
global $wgRequest, $wgJsMimeType;
$action = $wgRequest->getText('action');
if( $wgAllowUserJs && $this->loggedin ) {
if( $allowUserJs && $this->loggedin ) {
if( $this->mTitle->isJsSubpage() and $this->userCanPreview( $action ) ) {
# XXX: additional security check/prompt?
$this->userjsprev = '/*<![CDATA[*/ ' . $wgRequest->getText('wpTextbox1') . ' /*]]>*/';

View file

@ -496,6 +496,8 @@ class PreferencesForm {
$wgOut->setArticleRelated( false );
$wgOut->setRobotpolicy( 'noindex,nofollow' );
$wgOut->disallowUserJs(); # Prevent hijacked user scripts from sniffing passwords etc.
if ( $this->mSuccess || 'success' == $status ) {
$wgOut->addWikitext( '<div class="successbox"><strong>'. wfMsg( 'savedprefs' ) . '</strong></div>' );
} else if ( 'error' == $status ) {

View file

@ -18,10 +18,10 @@ class SkinStandard extends Skin {
/**
*
*/
function getHeadScripts() {
function getHeadScripts( $allowUserJs ) {
global $wgStylePath, $wgJsMimeType, $wgStyleVersion;
$s = parent::getHeadScripts();
$s = parent::getHeadScripts( $allowUserJs );
if ( 3 == $this->qbSetting() ) { # Floating left
$s .= "<script language='javascript' type='$wgJsMimeType' " .
"src='{$wgStylePath}/common/sticky.js?$wgStyleVersion'></script>\n";