25

According to Postgres's documentation, Postgres's password authentication method uses MD5 hashing to secure the password:

The password-based authentication methods are md5 and password. These methods operate similarly except for the way that the password is sent across the connection, namely MD5-hashed and clear-text respectively.

If you are at all concerned about password "sniffing" attacks then md5 is preferred. Plain password should always be avoided if possible. However, md5 cannot be used with the db_user_namespace feature. If the connection is protected by SSL encryption then password can be used safely (though SSL certificate authentication might be a better choice if one is depending on using SSL).

I've heard from numerous sources that the MD5 hashing algorithm is no longer considered secure. Does this mean that I should avoid using password-based authentication for Postgres? If so, which alternative method should I use?

Anders
  • 64,406
  • 24
  • 178
  • 215
Ajedi32
  • 4,637
  • 2
  • 26
  • 60

4 Answers4

23

If using SSL, then what PostgreSQL does is fine. If not using SSL, but still doing the authentication across the network, then what PostgreSQL does stinks. Their games with MD5 are worthless, but not because they use MD5. MD5 has its own issues, but there they are just misusing it awfully.

With "cleartext password" authentication, the client shows a user name and a password, and the server accepts them if they match what the server stored.

With "md5" authentication, the client shows a value (which happens to be the MD5 hash of the concatenation of the password and the user name) and the server accepts it if it matches what the server stored.

So you see it: in both cases, the client shows a bunch of bytes to the server, always the same sequence. It suffices for an attacker to tap on the network to observe these bytes, and then connect to the server and sends the same bytes to be granted entry. That the bytes are the result of a MD5 hash is completely irrelevant here. This MD5 hash is said to be password equivalent. As long as the connection can be eavesdropped at all (i.e. no SSL), then security goes down the drain.

See this page for the details of the MD5 computation. They call it "encryption", which it is not at all (hashing is not encryption).

We could even argue that using this MD5 decreases security: when a plaintext password is used, it can be forwarded to another authentication server (using Kerberos, LDAP,...) and that authentication server could then employ strong storage techniques (see password hashing). With the PostgreSQL-specific MD5 hash, this cannot apply. When the "md5" authentication method is used, it MUST be against a table in the database which contains all these "md5" value as is. An attacker who can get his hands on, say, a backup tape or an old disk, will immediately obtain many free accounts on the database.

And, I insist, nothing in all this has anything to do with MD5 cryptographic weaknesses. All of this would still apply if MD5 was replaced with SHA-512.

Tom Leek
  • 168,808
  • 28
  • 337
  • 475
  • 3
    @Tom_Leek - could you revise your answer in light of the answer below and the use of random salt? To me it seems like it has the strength of challenge-response and is not susceptible to replay? – Konrads Aug 25 '15 at 08:02
  • 4
    @Konrads, yes, it is not susceptible to replay when the md5 auth-method is used. Nevertheless, the problem with this method is it's the client-side hashing. The hash in the pg_shadow table is now a _password equivalent_. When an attackers steals this table (we assume this will happen eventually), she just uses any hash for authentication without even spending time to crack md5. – koddo Nov 02 '15 at 16:40
  • The only mitigating factor is that with the server sending a different salt/challenge for each authentication request, a replay attack would only work during a session. But the damning aspect is that a replay attack will still work during a session. – Craig Tullis Jun 23 '17 at 23:11
  • @Craig you mean stealing a session? Otherwise if you re-authenticate you got a new salt, so no replay there? – Jean Monet Feb 02 '21 at 17:50
11

Yes, using MD5 is safe. When a client wants to authenticate, the server sends a random salt value. The client uses that value, along with the password to generate a MD5 hash. Because a random salt is used, an attacker can not use a dictionary attack. Also, because the salt is changed each time a client authenticates, this is no ability to replay old authentication requests.

Details here in the AuthenticationMD5Password section.

Athir Nuaimi
  • 219
  • 2
  • 2
  • 1
    Ah: "`concat('md5', md5(concat(md5(concat(password, username)), random-salt)))`" Yeah, that's definitely safer than the method Tom Leek assumed in his answer. I wonder though if the cryptographic weaknesses of MD5 might come into play here. Could MD5's [weaker-than-expected preimage resistance](https://en.wikipedia.org/wiki/MD5#Preimage_vulnerability) be a problem for the security of this scheme? – Ajedi32 Aug 25 '15 at 17:21
  • Also, while this scheme might preserve password secrecy in the event of a MITM, I'm guessing it won't protect the privacy or security of the connection itself, right? Or is that password used to encrypt the connection somehow? – Ajedi32 Aug 25 '15 at 17:23
  • 2
    Also, it looks like Tom Leek's assertion that "An attacker who can get his hands on, say, a backup tape or an old disk, will immediately obtain many free accounts on the database." still applies here. Either `md5(concat(password, username))` or `password` has to be stored in plaintext in the database somewhere in order for Postgres to authenticate the connection, and if the attacker gets his hands on either of those values he can use it to authenticate to the database. – Ajedi32 Aug 25 '15 at 17:28
  • backup files should always be encrypted. And your production server should have the database on an encrypted drive. – Athir Nuaimi Aug 30 '15 at 22:42
  • True, but encryption is just another layer of security. It's not an excuse for storing unhashed password-equivalents in your DB. – Ajedi32 Aug 30 '15 at 22:46
3

TLDR. It can be secure if you configure it properly and use good long passwords.

1. In postgres the md5 auth-method means client-side hashing (discussions: 1, 2), which makes hashes password equivalent. A hash in the db is compared to a hash received from a client. An attacker can use any hash from stolen pg_shadow table directly, without even spending time to crack the md5.

It's much safer to assume the hashes will be stolen eventually and to avoid client-side hashing.


You can actually just take a look at the code, it's quite simple: https://github.com/postgres/postgres/blob/master/src/backend/libpq/crypt.c#L141 <— direct link to this line:

 if (strcmp(crypt_client_pass, crypt_pwd) == 0)

See what happens when the port->hba->auth_method == uaMD5. Yes, one can't intercept a hash clear-text, it's again salted and hashed. But when stolen by any other attack, it can be used directly without cracking.


2. Unsurprisingly, you can use server-side md5 hashing with postgres by using the password auth-method and create user whatever with encrypted password.

These methods operate similarly except for the way that the password is sent across the connection, namely MD5-hashed and clear-text respectively.

Use SSL to protect the clear-text password. You probably should know the way its hash is stored — the salt is reused:

 /* Encrypt user-supplied password to match stored MD5 */
 if (!pg_md5_encrypt(client_pass,          // const char *passwd
                     port->user_name,      // const char *salt
                     strlen(port->user_name),
                     crypt_client_pass))   // char *buf

One could even create random generated throwaway usernames to use them as salt, but I'm not sure if it's a good idea, this is error prone.

While the general recommendation is to migrate from md5, it's still not broken for password hashing. Relevant question: Why do people still use/recommend MD5 if it is cracked since 1996?

Don't use short passwords. Long, high-quality random passwords are still safe.

For a quick estimation, these (unfortunately, quite old) links have some numbers:
http://blog.codinghorror.com/speed-hashing/
https://security.stackexchange.com/a/33684/41687

Update: thanks to RhodiumToad from #postgresql channel on irc.freenode.net for clarifying that md5 is still not broken for password hashing, good long passwords will save the day.

koddo
  • 183
  • 7
2

Please, have a look at this TCP Stream capture to a Postgres server from a client application (C# with Npgsql connector):

No SSL

There, you can see the md5 hash from password, username and salt (look at the black little arrow).

Now, let´s see how does it look when a secure connection is used (SSL/TLS):

enter image description here

As you can see, when using a secure connection, the MD5 result is not "visible" in the connection. So, you can consider this method of data exchange with a PostgreSQL secure (similar thing happens with a web server, other databases servers, etc). It´s always good to use a packet sniffer to understand what´s really happening with the data ;-)

Ignacio
  • 123
  • 4