How to Upgrade Your PostgreSQL Passwords to SCRAM

Jonathan S. Katz
PostgreSQL Security

In a lot of PostgreSQL environments, it’s common practice to protect user accounts with a password. Starting with PostgreSQL 10, the way PostgreSQL manages password-based authentication got a major upgrade with the introduction of SCRAM authentication, a well-defined standard that is a significant improvement over the current system in PostgreSQL. What’s better is that almost all PostgreSQL drivers now support this new method of password authentication, which should help drive further adoption of this method.

While it may be easy to take advantage of SCRAM authentication in new PostgreSQL deployments, there are a few steps involved in upgrading your existing systems to utilize this method. This article will briefly explain how SCRAM works in PostgreSQL (to try to encourage you to upgrade!) and then walk you through the steps of how to upgrade your existing PostgreSQL clusters to use SCRAM authentication.

A Very Brief Overview of SCRAM

Prior to PostgreSQL 10, password authentication was available using the md5 method (and well, there was also a plaintext for drivers that did not support md5), where PostgreSQL defined its own unique authentication scheme. Using this authentication method, passwords are stored like this in PostgreSQL:

'md5' || md5(password + username)

While this method works, it does present a few challenges:

  1. If you have access to someone's username / password combination, or their PostgreSQL MD5-styled hash, you could log into any PostgreSQL cluster where the user has the same username / password.
  2. Even though it is fairly simple for each PostgreSQL driver to implement support for this method, It does not follow any particular standard. Without going into details, know that the "shared secret" between the PostgreSQL client and server is effectively shared over the wire every time the PostgreSQL-style md5 authentication method is used.

The Salted Challenge Response Authentication Mechanism, aka SCRAM, is designed to allow two parties to both verify that they know a shared secret (e.g. a password) without ever sending the secret between each other. To make this less abstract, in PostgreSQL, SCRAM is used so that the PostgreSQL server can verify that the client knows the correct password, and likewise, the client can verify that the server knows the correct password too, all without ever sending the actual password, not even in a hashed format!

What’s better, SCRAM is a defined standard (RFC5802); PostgreSQL implements SCRAM-SHA-256 (RFC7677), with the notable difference in that it uses the SHA-256 hashing function instead of SHA-1.

Going into how SCRAM authentication works is a much longer topic (and one that I definitely like to talk about). The rest of this article explains how to upgrade your current systems to take advantage of SCRAM authentication.

Upgrading to SCRAM Authentication

Step 0: Determine if you can upgrade to SCRAM

There are two key criteria to determine if you can upgrade your password-based authentication systems to use SCRAM:

  1. You are running PostgreSQL 10 or above
  2. All of the drivers that are used to connect to your PostgreSQL cluster have SCRAM compatibility. The PostgreSQL community has conveniently provided a list of drivers as well as if they support SCRAM

If your system meets both of those criteria, you can begin the process of upgrading to SCRAM!

Step 1: Validate your pg_hba.conf settings

The PostgreSQL pg_hba.conf file determines how your clients can connect to PostgreSQL. If you’ve looked at your pg_hba.conf file, you may have also noticed a line similar to this one:

# TYPE	DATABASE		USER		ADDRESS		METHOD
local	all				all						md5

The above states that any user trying to connect to your PostgreSQL cluster through a local connection (e.g. a UNIX socket) must use the md5 authentication method. For the purposes of upgrading to SCRAM, ensure that your password-based authentication methods are set to md5 - we will change this setting later once all of the passwords are upgraded.

Step 2: Change PostgreSQL's password_encryption method

In your postgresql.conf configuration file there is a setting called password_encryption that determines how passwords should be hashed. At this point, it's likely set to md5. To begin the upgrade process, you need to switch this value to scram-sha-256 i.e.

password_encryption = scram-sha-256

When this is done, you will have to reload your PostgreSQL cluster (a restart is not required).

Step 3: Determine Who Needs to Upgrade

The next step is to determine which of your users need to upgrade their passwords. As you may not be able to set all of their passwords on your own, you may want to reach out to these users to have them upgrade their passwords. To determine who needs to upgrade their passwords to SCRAM, as a privileged user (e.g. a superuser), you can run this SQL:

SELECT
    rolname, rolpassword ~ '^SCRAM-SHA-256\$' AS has_upgraded
FROM pg_authid
WHERE rolcanlogin;

This query looks for users that have the LOGIN privilege (i.e. they can login to your PostgreSQL cluster) and determines if their password still exists in a PostgreSQL-style MD5 hash. If has_upgraded is FALSE, then the user needs to re-hash their password.

Note: there are some extreme edge cases where the above query will register a false positive (e.g. if you've had a plaintext password that starts with SCRAM-SHA-256$) but in all likelihood, the above should work.

Step 4: Upgrade the Password

There are two recommended ways to re-hash the password:

Upgrade Method #1: via \password in psql

Using the command-line interface from psql, you can use the \password command, i.e:

\password

Or if you want to set the password for someone else on your system:

\password username

You will be prompted to enter a new password. This new password will be converted to a SCRAM verifier, and the upgrade for this user will be complete.

Upgrade Method #2: Create your own SCRAM Verifier + ALTER ROLE

The second method is to create your own SCRAM verifier and then user ALTER ROLE username PASSWORD '$SCRAM_VERIFIER'. I've written a little Python script (using Python 3.7) that helps with this:

https://gist.github.com/jkatz/e0a1f52f66fa03b732945f6eb94d9c21

which is also embedded below for convenience:

 

If you are able to successfully run the script, you should receive output that looks similar to:

SCRAM-SHA-256$4096:UrxBRgDElbaS4iwfRzn59g==$SErsniXa5gEr03cXhcFPLSM4C/22IKTJ9emThT+wPrM=:rSaLPYfC3eor3cq3f1Zq6Dw2Rl7HwIUHCMP7avpJQak=

This is an example of a SCRAM verifier that PostgreSQL stores and is used during SCRAM authentication. If I want to set this to be used as part of my new password:

ALTER ROLE jkatz
    PASSWORD 'SCRAM-SHA-256$4096:UrxBRgDElbaS4iwfRzn59g==$SErsniXa5gEr03cXhcFPLSM4C/22IKTJ9emThT+wPrM=:rSaLPYfC3eor3cq3f1Zq6Dw2Rl7HwIUHCMP7avpJQak=';

Why Not "ALTER ROLE username PASSWORD 'newpassword';"?

While the above command will re-hash your password, one side effect is that your plaintext password could end up being logged based on your cluster logging settings! As such, it effectively defeats one of the nice advantages of SCRAM, i.e. not having to expose the shared secret between two parties. So please don't use the above method.

Step 5: Update pg_hba.conf to use only "scram-sha-256"

Here's a fun fact: to ease the upgrade, your applications can still perform SCRAM verification even if md5 is chosen as the authentication method! If a user account has already had its password upgraded into a SCRAM verifier, it will use SCRAM authentication even if md5 is the authentication method!

However, once all the passwords are upgraded, you will want to update your pg_hba.conf file and switch all of your entries that use md5 to now use scram-sha-256. First, check that all of your users have been upgraded to use SCRAM, i.e.:

SELECT
    rolname, rolpassword ~ '^SCRAM-SHA-256\$' AS has_upgraded
FROM pg_authid
WHERE rolcanlogin;

returns TRUE for has_upgraded for all of your users.

Then, modify your md5 entires in your pg_hba.conf file to use scram-sha-256 e.g. using my example above:

# TYPE	DATABASE		USER		ADDRESS		METHOD
local	all				all						scram-sha-256

When this is done, you will have to reload your PostgreSQL cluster (a restart is not required).

Congratulations! All of your PostgreSQL user accounts will be upgraded to authenticate using SCRAM!

Read More

Crunchy News

Join the Discussion