Make number of PBKDF2 iterations used for deriving session secret configurable

The intent is both to allow the number of iterations to be dialed up (either as
computational power increases, or on the basis of security needs) and dialed
down for the unit tests, where hash_pbkdf2() calls account for 15-40% of wall
time. The number of iterations is stored in the session, so changing the number
of iterations does not cause existing sessions to become invalid or corrupt.
Sessions that do not have wsSessionPbkdf2Iterations set (i.e., sessions which
precede this change) are transparently upgraded.

Change-Id: I084a97487ef4147eea0f0ce0cdf4b39ca569ef52
This commit is contained in:
Ori Livneh 2016-05-28 06:25:48 -07:00
parent b74c4b2f95
commit acca48094c
4 changed files with 20 additions and 3 deletions

View file

@ -9,6 +9,8 @@ production.
* The load.php entry point now enforces the existing policy of not allowing
access to session data, which includes the session user and the session
user's language. If such access is attempted, an exception will be thrown.
* The number of internal PBKDF2 iterations used to derive the session secret
is configurable via $wgSessionPbkdf2Iterations.
=== New features in 1.28 ===
* User::isBot() method for checking if an account is a bot role account.

View file

@ -2386,6 +2386,13 @@ $wgSessionHandler = null;
*/
$wgPHPSessionHandling = 'enable';
/**
* Number of internal PBKDF2 iterations to use when deriving session secrets.
*
* @since 1.28
*/
$wgSessionPbkdf2Iterations = 10001;
/**
* If enabled, will send MemCached debugging information to $wgDebugLogFile
*/

View file

@ -384,7 +384,7 @@ final class Session implements \Countable, \Iterator, \ArrayAccess {
* @return string[] Encryption key, HMAC key
*/
private function getSecretKeys() {
global $wgSessionSecret, $wgSecretKey;
global $wgSessionSecret, $wgSecretKey, $wgSessionPbkdf2Iterations;
$wikiSecret = $wgSessionSecret ?: $wgSecretKey;
$userSecret = $this->get( 'wsSessionSecret', null );
@ -392,8 +392,13 @@ final class Session implements \Countable, \Iterator, \ArrayAccess {
$userSecret = \MWCryptRand::generateHex( 32 );
$this->set( 'wsSessionSecret', $userSecret );
}
$iterations = $this->get( 'wsSessionPbkdf2Iterations', null );
if ( $iterations === null ) {
$iterations = $wgSessionPbkdf2Iterations;
$this->set( 'wsSessionPbkdf2Iterations', $iterations );
}
$keymats = hash_pbkdf2( 'sha256', $wikiSecret, $userSecret, 10001, 64, true );
$keymats = hash_pbkdf2( 'sha256', $wikiSecret, $userSecret, $iterations, 64, true );
return [
substr( $keymats, 0, 32 ),
substr( $keymats, 32, 32 ),

View file

@ -75,7 +75,7 @@ class PHPUnitMaintClass extends Maintenance {
global $wgLanguageConverterCacheType, $wgUseDatabaseMessages;
global $wgLocaltimezone, $wgLocalisationCacheConf;
global $wgDevelopmentWarnings;
global $wgSessionProviders;
global $wgSessionProviders, $wgSessionPbkdf2Iterations;
global $wgJobTypeConf;
global $wgAuthManagerConfig, $wgAuth, $wgDisableAuthManager;
@ -125,6 +125,9 @@ class PHPUnitMaintClass extends Maintenance {
],
];
// Single-iteration PBKDF2 session secret derivation, for speed.
$wgSessionPbkdf2Iterations = 1;
// Generic AuthManager configuration for testing
$wgAuthManagerConfig = [
'preauth' => [],