diff options
Diffstat (limited to 'includes/User.php')
-rw-r--r-- | includes/User.php | 77 |
1 files changed, 40 insertions, 37 deletions
diff --git a/includes/User.php b/includes/User.php index cebcf604..705fd291 100644 --- a/includes/User.php +++ b/includes/User.php @@ -831,23 +831,20 @@ class User { } /** - * Return a random password. Sourced from mt_rand, so it's not particularly secure. - * @todo hash random numbers to improve security, like generateToken() + * Return a random password. * * @return String new random password */ public static function randomPassword() { global $wgMinimalPasswordLength; - $pwchars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz'; - $l = strlen( $pwchars ) - 1; - - $pwlength = max( 7, $wgMinimalPasswordLength ); - $digit = mt_rand( 0, $pwlength - 1 ); - $np = ''; - for ( $i = 0; $i < $pwlength; $i++ ) { - $np .= $i == $digit ? chr( mt_rand( 48, 57 ) ) : $pwchars[ mt_rand( 0, $l ) ]; - } - return $np; + // Decide the final password length based on our min password length, stopping at a minimum of 10 chars + $length = max( 10, $wgMinimalPasswordLength ); + // Multiply by 1.25 to get the number of hex characters we need + $length = $length * 1.25; + // Generate random hex chars + $hex = MWCryptRand::generateHex( $length ); + // Convert from base 16 to base 32 to get a proper password like string + return wfBaseConvert( $hex, 16, 32 ); } /** @@ -877,7 +874,7 @@ class User { $this->mTouched = '0'; # Allow any pages to be cached } - $this->setToken(); # Random + $this->mToken = null; // Don't run cryptographic functions till we need a token $this->mEmailAuthenticated = null; $this->mEmailToken = ''; $this->mEmailTokenExpires = null; @@ -984,11 +981,11 @@ class User { return false; } - if ( $request->getSessionData( 'wsToken' ) !== null ) { - $passwordCorrect = $proposedUser->getToken() === $request->getSessionData( 'wsToken' ); + if ( $request->getSessionData( 'wsToken' ) ) { + $passwordCorrect = $proposedUser->getToken( false ) === $request->getSessionData( 'wsToken' ); $from = 'session'; - } elseif ( $request->getCookie( 'Token' ) !== null ) { - $passwordCorrect = $proposedUser->getToken() === $request->getCookie( 'Token' ); + } elseif ( $request->getCookie( 'Token' ) ) { + $passwordCorrect = $proposedUser->getToken( false ) === $request->getCookie( 'Token' ); $from = 'cookie'; } else { # No session or persistent login cookie @@ -1083,6 +1080,9 @@ class User { $this->decodeOptions( $row->user_options ); $this->mTouched = wfTimestamp(TS_MW,$row->user_touched); $this->mToken = $row->user_token; + if ( $this->mToken == '' ) { + $this->mToken = null; + } $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated ); $this->mEmailToken = $row->user_email_token; $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires ); @@ -1989,10 +1989,14 @@ class User { /** * Get the user's current token. + * @param $forceCreation Force the generation of a new token if the user doesn't have one (default=true for backwards compatibility) * @return String Token */ - public function getToken() { + public function getToken( $forceCreation = true ) { $this->load(); + if ( !$this->mToken && $forceCreation ) { + $this->setToken(); + } return $this->mToken; } @@ -2006,14 +2010,7 @@ class User { global $wgSecretKey, $wgProxyKey; $this->load(); if ( !$token ) { - if ( $wgSecretKey ) { - $key = $wgSecretKey; - } elseif ( $wgProxyKey ) { - $key = $wgProxyKey; - } else { - $key = microtime(); - } - $this->mToken = md5( $key . mt_rand( 0, 0x7fffffff ) . wfWikiID() . $this->mId ); + $this->mToken = MWCryptRand::generateHex( USER_TOKEN_LENGTH ); } else { $this->mToken = $token; } @@ -2718,6 +2715,14 @@ class User { $this->load(); if ( 0 == $this->mId ) return; + if ( !$this->mToken ) { + // When token is empty or NULL generate a new one and then save it to the database + // This allows a wiki to re-secure itself after a leak of it's user table or $wgSecretKey + // Simply by setting every cell in the user_token column to NULL and letting them be + // regenerated as users log back into the wiki. + $this->setToken(); + $this->saveSettings(); + } $session = array( 'wsUserID' => $this->mId, 'wsToken' => $this->mToken, @@ -2795,7 +2800,7 @@ class User { 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ), 'user_options' => '', 'user_touched' => $dbw->timestamp( $this->mTouched ), - 'user_token' => $this->mToken, + 'user_token' => strval( $this->mToken ), 'user_email_token' => $this->mEmailToken, 'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ), ), array( /* WHERE */ @@ -2862,7 +2867,7 @@ class User { 'user_email_authenticated' => $dbw->timestampOrNull( $user->mEmailAuthenticated ), 'user_real_name' => $user->mRealName, 'user_options' => '', - 'user_token' => $user->mToken, + 'user_token' => strval( $user->mToken ), 'user_registration' => $dbw->timestamp( $user->mRegistration ), 'user_editcount' => 0, ); @@ -2896,7 +2901,7 @@ class User { 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ), 'user_real_name' => $this->mRealName, 'user_options' => '', - 'user_token' => $this->mToken, + 'user_token' => strval( $this->mToken ), 'user_registration' => $dbw->timestamp( $this->mRegistration ), 'user_editcount' => 0, ), __METHOD__ @@ -3144,7 +3149,7 @@ class User { } else { $token = $request->getSessionData( 'wsEditToken' ); if ( $token === null ) { - $token = self::generateToken(); + $token = MWCryptRand::generateHex( 32 ); $request->setSessionData( 'wsEditToken', $token ); } if( is_array( $salt ) ) { @@ -3161,8 +3166,7 @@ class User { * @return String The new random token */ public static function generateToken( $salt = '' ) { - $token = dechex( mt_rand() ) . dechex( mt_rand() ); - return md5( $token . $salt ); + return MWCryptRand::generateHex( 32 ); } /** @@ -3268,12 +3272,11 @@ class User { global $wgUserEmailConfirmationTokenExpiry; $now = time(); $expires = $now + $wgUserEmailConfirmationTokenExpiry; - $expiration = wfTimestamp( TS_MW, $expires ); - $token = self::generateToken( $this->mId . $this->mEmail . $expires ); - $hash = md5( $token ); $this->load(); + $token = MWCryptRand::generateHex( 32 ); + $hash = md5( $token ); $this->mEmailToken = $hash; - $this->mEmailTokenExpires = $expiration; + $this->mEmailTokenExpires = wfTimestamp( TS_MW, $expires ); return $token; } @@ -3828,7 +3831,7 @@ class User { if( $wgPasswordSalt ) { if ( $salt === false ) { - $salt = substr( wfGenerateToken(), 0, 8 ); + $salt = MWCryptRand::generateHex( 8 ); } return ':B:' . $salt . ':' . md5( $salt . '-' . md5( $password ) ); } else { |