Table of Contents

Plain or hashed password storage?

"Hashed!" I hear you say. It's true, if you are looking for the ultimate security then you should use the hashed authentication provider, but you should also ensure all your users are using up-to-date clients, encryption, and verifying your server's certificate (not just blindly clicking "OK" to warnings). The account database is not the easiest place for an attacker to get passwords from.

In summary: it is easier to secure your server than to secure users' clients and educate users about security.

The Technical Bit

What do you mean by "hashed"?

Many people confuse "hashing" with "encrypting". Hashing is a one-way process that converts an input into an output from which the original password cannot be recovered. Encrypting a password, however, implies that the password can be "decrypted". Obviously if you store passwords encrypted then the server must be able to decrypt them, so it needs a key. If you store the key on the same server as your password database then the attacker can simply get both when they break into your server.

For this reason, Prosody only supports hashing passwords.

Authenticating

XMPP uses a generic authentication protocol known as SASL (not to be confused with Cyrus SASL, a specific SASL implementation). SASL supports a number of authentication mechanisms, however there are a few main ones used in XMPP today: PLAIN, DIGEST-MD5, SCRAM-SHA-1.

PLAIN

The PLAIN mechanism is simple. The client transmits the username and password to the server, and the server compares it with what it has in the database. If it has the plaintext password in the database, it can compare this directly with the password it received from the client. If it has a hashed password stored, it hashes the password from the client and compares the hashes.

Since this mechanism sends the password in the clear, it should not be used on unencrypted connections. This means also that the user should verify the server's certificate. Encryption is of little use if you don't verify the identity of the server you are encrypting to.

DIGEST-MD5

By far the most common mechanism used in XMPP today. This is a more advanced SASL mechanism published in 2000 that actually sends a calculated hash of the password to the server, instead of a plaintext one. Unfortunately to verify that the hash is the correct hash of the user's password, the server needs access to the user's plaintext password to calculate it.

Because the hash the client sends is not just a hash of the password, but also of a random number, the hash changes every time (this is to prevent the attacker capturing a single hash and using it for login in the future) - which means the server cannot store it in the database.

DIGEST-MD5 also has a basic mechanism to verify that the server does have access to its password. This is a form of "mutual authentication", and gives the client confidence that it is connected to the right server, even if the connection is encrypted with an unverified certificate (it does not protect against eavesdroppers, however).

However, because DIGEST-MD5 had a number of issues it was formally obsoleted in 2011.

SCRAM-SHA-1

This shiny new mechanism was published in 2010. It aims to solve all the problems in prior mechanisms, and fix their weaknesses. In particular it:

Unfortunately there's a catch. Since SCRAM is so new, most clients in the wild do not implement it (even though support is in or being added to most clients, many users have not upgraded yet). This causes two problems:

On the other hand, when the server is storing the plaintext password in the database, it needs to calculate the SCRAM hash to clients that try to log in with SCRAM-SHA-1. This makes the hashed storage much more attractive if all your clients support SCRAM.

SCRAM-SHA-1-PLUS

Similar to regular SCRAM-SHA-1, but with a feature called channel binding, wherein the hashes are bound to the specific TLS session. This means that the authentication handshake would fail during an Man-in-the-Middle attack, where you would have an TLS session to the attacker instead of your server and the attacker has another TLS session to the server.

Conclusion

Plain or hashed? You decide. For now Prosody's default remains "plain". However in the future when more clients support SCRAM out of the box the choice is clear.