5

I am using a Postgres 9.3 database as a back-end for a web application. I use PHP 5.5.7 to connect to the database and return JSON for the front-end AJAX calls.

I'm trying to decide on where to put the user authentication logic.

I am not a security expert; however, I am familiar with PHP's new password_*() functions and I have a strong grasp of what is going on under the hood. I am also familiar with the Postgres Extension pgcrypto and the associated crypt() function.

My question is, does it make sense to use PHP or Postgres to hash passwords?

I was curious as to how these functions differ, so I made a password hash in PHP and then gave it to Postgres to see if Postgres uses the same algorithm. Given the same parameters, Postgres returned a different result when compared to PHP (not unexpected, but with noting).

PHP

password_hash('password', PASSWORD_BCRYPT, ["cost" => 15]);

output: $2y$15$o8JufrnVXoob2NKiEGx6.uI4O2D4VcaAmY7WtNq5zPFiJow4KohGu

Postgres

SELECT '$2y$15$o8JufrnVXoob2NKiEGx6.uI4O2D4VcaAmY7WtNq5zPFiJow4KohGu' = crypt('password', '$2y$15$o8JufrnVXoob2NKiEGx6.uI4O2D4VcaAmY7WtNq5zPFiJow4KohGu')

output: false


PHP vs. Postgres

Given that these processes are different, I wonder if one is better then the other? Is one more, or less, secure?

Some other thoughts:

I currently have all logic stored in the database (in views, functions, constraints, etc.) so if I ever need to use a different front-end I don't have to worry about missing logic. Calculating password hashes in PHP would effectively require all requests to pass through PHP to access the database.

On the other hand, putting the logic in the database would allow me the flexibility to use other connection options; however, all of the Postgres queries are logged. I can't disable the logs because of the WAL used in replication. This seems like a big security hole.

Am I on the right track here? What am I missing?


EDIT

I just looked at another message thread and found some more information.

  1. Putting the logic in Postgres would require the database to processes and perform the hash operation. This would be a bad thing for other users and batch jobs that need those resources.
  2. Not only would the hash slow down normal operations, it would make the whole system more vulnerable to DOS attacks.

Our simple web servers with load balancing would address both issues...

Again, am I on the right track here? What else am I missing?

losthorse
  • 1,530
  • 1
  • 13
  • 33

1 Answers1

3

For the difference between versions 2y and 2a, see this thread and the various links within it:

https://security.stackexchange.com/questions/20541/insecure-versions-of-crypt-hashes

My understanding is there was a problem with the 2a implementation in PHP until v.5.3.8, though only for strings that contained non-ascii chars. PgCrypto, as you noted, doesn't "speak" 2y for some reason, and I'd assume it suffers so such problem. (Perhaps report this as a bug?)

Apart from the points raised in the latter, you nailed the main security difference between the two in your question: systematically hashing the password within the database is convenient but implies that you send it to your database in clear text, where it can (and will) be logged — or snooped at outright, if your DB connection is not encrypted.

In an ideal world, you'd hash the password in the client app using javascript before it's even sent to PHP. The next best thing is to send it using SSL to PHP, then hash it using PHP before sending it to the DB.

Aside: I'm pretty certain that PHP's crypt can generate a (secure) 2a version hash if you need interoperability for some reason.

Community
  • 1
  • 1
Denis de Bernardy
  • 75,850
  • 13
  • 131
  • 154
  • Creating the hash client side is an interesting idea... the problem I see is that with each attempt to verify a password I would then need to send the salt (unique and random for each password) to the client for the hash to process. This seems like a problem given the fact that the client would then have access to both the algorithm used and the salt for any username the client supplies. – losthorse Jan 02 '14 at 15:51
  • Hashing on the client side is likely not a good idea. [Check out why](http://www.matasano.com/articles/javascript-cryptography/)... – ircmaxell Jan 02 '14 at 17:22
  • @ircmaxell: as I read the article you linked to, the issue is about delivering the crypto keys in a secure manner, and that is indeed a problem but only for two way cryptography. When hashing a password, the only thing you need is a good RNG within the browser itself, in order to generate the salt. (And I seem to remember the sjcl having one.) – Denis de Bernardy Jan 03 '14 at 11:35
  • @losthorse: yes, you have it correct for your second set of questions. But note that the door for ddos is basically the same for the db or php. The only real difference is which cpu gets pillaged by malicious hashing. – Denis de Bernardy Jan 03 '14 at 11:38