2

Basic Assumptions

Let us assume I work for a company, which aims to authenticate users using traditional usernames and passwords. The company currently uses a slow key-derivation function to hash passwords, such as Argon2, scrypt or PBKDF2.

It is further assumed that a network HSM can calculate the HMAC of a string with a stored key, but cannot calculate a KDF on its own.

The Idea

One of the developers now had an idea of using a Hardware Security Module to further secure the credentials. He had the idea to use the HMAC of the password as the input for the key derivation function. Since the actual key for the HMAC function is stored inside the HSM and can't be extracted. So here in pseudo-code is once the old login code, and the new login code:

// Old Login Code
function Authenticate(input)
{
    user = DB.getUser(input.username);
    if (user == null) return false; //User does not exist

    kdf = Argon2id;
    return kdf.verify(user.password, input.password);
}

And here is the new login code:

// New Login Code
function Authenticate(input)
{
    user = DB.getUser(input.username);
    if (user == null) return false; //User does not exist

    kdf = Argon2id;

    keyedHash = HSM.getHMAC(input.password, useInternalKey=true);
    return kdf.verify(user.password, keyedHash);
}

My Reasoning

This seems to overall improve the security, because an attacker who is able to steal the database, would also need access to the HSM to attempt to crack the keys. Even if an attacker knows their own password, the key stored inside the HSM is sufficiently long that attempting to brute-force the key would not be feasible.

While an attacker with control over the database might be able to send password candidates to the HSM to get the keyed hashes in return, it will:

  • severely limit the amount of candidates the attacker can attempt per second
  • likely cause the network administrators to see unusual network traffic and detect the breach

Possible Downsides

I am aware of "Never Roll Your Own!", and I believe that this is not "my own algorithm".

Furthermore, I understand that, should the HSM ever lose the key, users would now not be able to log in anymore. This problem could be solved with using a backup HSM and storing the key there as well.

My question

Does this scheme make any sense? Does it actually prevent an attacker from being able to recover passwords? Or is it just an excuse for the IT team to spend lots of money to get a shiny new thing?

3
  • Although the scheme does make sense to me, you have bigger problems if an attacker obtains database access. What kind of application are we talking about? Or perhaps what industry is the application used in? I know that such approaches are used in the financial industries. If an attacker could obtain the database and the database holds sensitive (PII) data, the HSM is not going to help you here.
    – Jeroen
    Jul 9, 2019 at 14:10
  • @Jeroen-ITNerdbox It's a purely fictional scenario, and login credentials are the only sensitive information in this case.
    – user163495
    Jul 9, 2019 at 15:23
  • 1
    If it's a purely fictional scenario, why waste resources defending against it?
    – anon
    Jul 9, 2019 at 16:38

2 Answers 2

1

This is a standard, highly-secure way to combine a slow, salted password hash with a "pepper" (or "secret salt") that ensures, even in the case of complete exposure of your auth database, attackers cannot crack any of the passwords without further compromise. You can do this in software: compute the HMAC with a secret that might be stored in the server process, in an OS-protected area that won't reveal the key to user-mode processes, or in another machine on the network via some form of RPC (in increasing levels of security). The last approach is effectively a software "HSM" and is sometimes used as a cheaper alternative to a true HSM.

It's possible to reverse the order of HMAC and password hash - run the password through your slow salted hash, and then HMAC it and check the result against the value in the DB - but this doesn't work with things like your kdf.verify function. Perhaps more interestingly, with a scheme like this it's also possible to do away with the slow password hash altogether, if you're sufficiently sure the HSM (or whatever you use to compute the HMAC) is secure enough. Compromising either the HSM or the DB still won't provide enough information to crack users' credentials (although the server itself is a single point of failure, of course, since it has access to both and also sees passwords as they are sent by users). However, if the attacker does get access to both, brute-forcing could proceed as fast as the attacker can ask the HSM for HMACs, so (IMO) it's still a good idea to have a slow hash function in there.

0

Firstly, Also check the "password" for a non existent user. (other wise you leak whether an account exists or not [blind timing based attack]).

Storing the passwords in the HSM would limited the exposure of credentials with a data leak (a.k.a someone stole the databases).

It would not interfere with someone with access to your machine though (since it can access the HSM itself directly.)

A better solution would be to separate out the authentication to a separate machine / part and have that contact the HSM or something like Vault over a secure (backbone) network. since the secrets are than not stored on the machine itself its no longer vulnerable for this threat in this way. you can limit (or flag) when the HSM or vault receives the same validation request in short succession (something that would happen often when compromised).

In short I would work more towards layering your authentication process instead of just siloing it up in a HSM.

You must log in to answer this question.