4

I'm currently using PostgreSQL with the pgcrypto extension to store and verify user passwords. When a user logs in, I compare the entered password with the stored hash using the following query:

SELECT id FROM users WHERE email = '[email protected]' AND password = crypt('entered_password', password); 

Note: In this example, the password is passed as a constant, but in the real application, a SQL injection-free method is used.

My understanding is that this approach could be insecure against timing attacks because the use of = operator in the query.

However, I want to confirm with security experts if this method is indeed secure and if there are any potential vulnerabilities or better practices I should be aware of.

Question: Is the use of crypt in this manner secure against timing attacks?

Thank you for your insights!

2
  • 3
    What do you mean by a "timing attack" in this context?CommentedOct 10, 2024 at 19:52
  • 1
    @RoyceWilliams: The OP means a side-channel attack on the string comparison similar to this one on HMACs. Based on time differences, the attacker might be able to determine at least a short prefix of the password hash and use this to pre-check passwords offline instead of having to test them all online (which may trigger a rate limit). The attack is definitely more difficult than the one on HMACs, since the input is hashed before the comparison. I still think it’s a valid concern.
    – Ja1024
    CommentedOct 12, 2024 at 22:14

1 Answer 1

13

No, a direct CHAR or VARCHAR comparison in PostgreSQL is not timing-safe.

PostgreSQL internally uses the memcmp function from the C standard library. At least in the GNU C Library (glibc), the function returns early as soon as it encounters a character that doesn't match – and it's hard to imagine any other implementation.

If you want a timing-safe comparison, you need to implement it yourself. You can, for example, iterate over all characters and compare them without returning early. Or you calculate a hash-based message authentication code (HMAC) of both operands and compare those HMACs. Since an attacker cannot calculate the HMACs themself (unless they've compromised the key), timing differences don't reveal anything useful about the password hashes.

Note that there are other issues:

  • The crypt function and its algorithms are largely obsolete. Only bcrypt (called bf in pgcrypto) is still somewhat acceptable, but far stronger algorithms like Argon2 have been developed since 1999 (when bcrypt was first published).
  • When you hash passwords in the database system, this means you have to transmit the plaintext password first. This greatly increases the risk of accidentally leaking the password, e.g., through the query log or in transit.

It's much better to hash the password in the application. This also lets you use more modern hash algorithms (like Argon2) which aren't currently implemented in pgcrypto.

16
  • And since it's easier to scale on web front-ends than on databases, it's better to have compute- and/or memory-intensive operations (modern hashes are supposed to be "expensive") on the front-end rather than in the DB.
    – jcaron
    CommentedOct 11, 2024 at 10:59
  • The = operator is not constant-time, but I don't see any reason that's relevant in this context. Assuming the attacker does not have access to the salt, knowing how many bytes of the computed hash matched for a candidate password is completely useless.CommentedOct 11, 2024 at 20:46
  • 2
    @R..GitHubSTOPHELPINGICE: The salt isn’t secret, so the system shouldn’t depend on the attacker not knowing the salt. One attack I could think of is the following: Assume that there’s strict rate limiting which prevents the attacker from efficiently performing a direct brute-force attack. Knowing the salt (and other hash parameters), they can calculate the hash corresponding to each password they try. By measuring the required time, they not only test the passwords but also get information about partial hash matches. This can be useful to rule out passwords before sending them to the server.
    – Ja1024
    CommentedOct 11, 2024 at 21:09
  • 1
    I don't get it; for all the things wrong with crypt; there's no obvious timing attack here.
    – Joshua
    CommentedOct 12, 2024 at 5:07
  • 1
    The problem is that in a real-life environment you have a lot of unpredictable delays between your request and server's response so you must send millions of requests to be able statistically extract this tiny delay which is caused by memcmp. That's why timing attacks are very theoretical in most cases.CommentedOct 12, 2024 at 21:58

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.