Password hash provider

From Sense/Net Wiki
Jump to: navigation, search
  • draft
  • 6.3
  • Enterprise
  • Community
  • Planned


The Sense/Net never stores passwords, only hashes generated from them. In order to use the best password hash policy in every Sense/Net installation we ensure a framework for hash generation from the users' password with a salt. Only the password-hash utilization is centralized (password check in login, forgotten password, old-password rules, export, import etc.) - which ensures the safety of the processes - but the hash generation is customizable.


The hash generation and password equality check are the PasswordHashProvider responsibility. The PasswordHashProvider is an abstract class of the Sense/Net that provides only static methods for the realization of the functionality and hides all implementation details. The hash generator can use a salt that is provided by an IPasswordSaltProvider implementation. The PasswordHashProvider must be configured if it is different from the built-in default. Sense/Net provides a mechanism that can migrate the old hashes if the PasswordHashProvider is changed (see below).


The PasswordHashProvider's functionality is three methods:

// Generates a hash from the given password with the saltProvider if there is.
public static string EncodePassword(string passwordInClearText, IPasswordSaltProvider saltProvider);
// Checks the password by the given hash and saltProvider with the configured or default PasswordHashProvider. According to configuration does the migration too.
public static bool CheckPassword(string passwordInClearText, string hash, IPasswordSaltProvider saltProvider);
// Checks the password by the given hash and saltProvider with the configured or default OutdatedPasswordHashProvider.
public static bool CheckPasswordForMigration(string passwordInClearText, string hash, IPasswordSaltProvider saltProvider);

Although these methods are public, tipically used in the user authentication process that is internal in the Sense/Net. The PasswordHashProvider specifies two methods for the inherited implementations:

// Implementation of the hash generator. Uses the saltProvider if there is.
protected abstract string Encode(string text, IPasswordSaltProvider saltProvider);
// Implementation of the checking of the password-hash match. Uses the saltProvider if there is.
protected abstract bool Check(string text, string hash, IPasswordSaltProvider saltProvider);

The PasswordHashProvider provides an instance method to use the saltProvider with the simplest way:

protected string GenerateSalt(IPasswordSaltProvider saltProvider)
    if (saltProvider == null)
        return string.Empty;
    return saltProvider.GetPasswordSalt();


An interface that specifies only one method:

string GetPasswordSalt();

Now the salt provider in Sense/Net is the user instance whose password is currently handled. Generally this implementation is on the Node class that uses the CreationDate as base of the salt generation. This behavior is overridable even class that is in the inheritance chain of the User class. The default salt generation method:

public virtual string GetPasswordSalt()
    return this.CreationDate.ToString("yyyyMMddHHmmssff");


There is a problem when the PasswordHashProvider is changed. The real migration needs the original passwords but the Sense/Net never stores passwords only the hashes. The most comfortable solution is the migration when the user is logging-in because in this time the password is pesented. The Sense/Net supports this method. The algorithm:

  • User posts her domain\name and password.
  • User instantiation by name and domain.
  • Checking password match by the instantiated user's PasswordHash property value and instantiated user as the salt provider. Hash provider is the configured under the "PasswordHashProvider" web config key.
  • If match, ok: user authenticated.
  • If migration is off: access denied.
  • Else checking password match with the old provider ("OutdatedPasswordHashProvider" web config key).
  • If not match: access denied.
  • Else encoding password with the configured hash provider ("PasswordHashProvider" web config key) and saving.
  • User is authenticated and her hash refreshed.
Full algorithm of the checking password-hash matching

Customization summary

In summary, the way of the customization is the following:

  • need to decide whether the built-in hash generator is good enough.
  • If not, implement a new generator and configure its typename in the configuration files with the PasswordHashProvider key.
  • You need to decide whether the built-in salt generator is good enough.
  • If not, override the public virtual string GetPasswordSalt() method on the used User class (other configuration is not needed).
  • Decide wether you need to migration the existing hashes.
  • If yes, do the migration in the following way:
    • Configure your old PasswordHashProvider under the "OutdatedPasswordHashProvider" key in the web.config. Old Sense/Net applications (before version 6.3) uses the default: configuration is not necessary.
    • Set to "true" the "EnablePasswordHashMigration" key in the web.config.
    • Wait until everyone logs in at least once. The password check method will migrate the hash with re-generation with the new provider after checking with the old provider.
    • Switch off the migration: comment out the EnablePasswordHashMigration key in the web.config.
    • If a user did not log-in in the migration period, she need to play the "forgotten password" process.

Configuration summary

This framework's configuration has 3 element:

  • PasswordHashProvider: contains the fully qualified name of the PasswordHashProvider if it is not the default. Default: SenseNet.ContentRepository.Storage.Security.SenseNetPasswordHashProvider.
  • EnablePasswordHashMigration: Master switch of the password hash migration. Default: false.
  • OutdatedPasswordHashProvider: fully qualified name of the old PasswordHashProvider that allows the old-way password checking only in the migration period. Default: SenseNet.ContentRepository.Storage.Security.Sha256PasswordHashProviderWithoutSalt. Relevant part of the web.config:
    <!-- Default password-hash provider. -->
    <!--<add key="PasswordHashProvider" value="SenseNet.ContentRepository.Storage.Security.SenseNetPasswordHashProvider" />-->
    <!-- Switch on migrating passwords. The security will be worse. -->
    <!--<add key="EnablePasswordHashMigration" value="true" />-->
    <!-- Default password-hash provider for password migration. This provider is used only the EnablePasswordHashMigration is true -->
    <!--<add key="OutdatedPasswordHashProvider" value="SenseNet.ContentRepository.Storage.Security.Sha256PasswordHashProviderWithoutSalt" />-->


Related links