16

According to http://nginx.org/en/docs/http/ngx_http_auth_basic_module.html nginx can read password hashes of these types:

crypt(), apr1, SHA1 & SSHA.

This is how I understand how these hashes work and what the problem with them is:

crypt() discards everything after the 8. character, so if my password is "12345678UltraSecurePa$$w0rd" I can successfully login with typing "12345678". Doesn't that defeat the purpose of a strong (lengthy) password? Brute forcing through 8 any character password seems to be trivial these days. I don't understand why crypt should be more secure than plaintext.

apr1 is MD5 but slowed down a thousand times. Which is still very weak these days. One can find reports of brute forcing through > 300.000.000.000 (300 billion) hashes per second with a couple GPUs.

SHA1 is not very much better than MD5, it is a hashing algorithm optimized to be fast and thus is vulnerable to brute force attacks. Also it is not salted in this case.

And the last method is salted SHA1. This seems to be the least weak method for hashing http basic auth passwords in nginx. But when someone steals the hash, he also has the salt (the salt is just base64 encoded), so SSHA still has the weakness of using fast hashing algorithms for "encrypting" passwords.

nginx can't use bcrypt, or PBKDF2.

To conclude: If I want that my HTTP basic auth hashes are "secure" (secure means that it is too time expensive to crack the hashes) I have to follow these rules:

  1. never use crypt.
  2. enforce passwords with at least 16 characters because this seems to be long enough against brute force attacks (let's just ignore dictionary attacks here for a moment).

And: convince the nginx guys that they should implement better hashing methods for HTTP basic auth.

Is there an error in my conclusion?

  • 2
    You could use the Nginx PAM module and use a PAM back-end with scrypt. But you need to consider the DoS impact of burning 0.5s CPU time for an unauthenticated request. – paj28 Dec 12 '13 at 16:25
  • 2
    Thanks for the answer. The DoS method could be mitigated by throttling, nginx is able to do this with the limit module nginx.org/en/docs/http/ngx_http_limit_req_module.html – ahofmann Dec 12 '13 at 17:09
  • Enforcing long passwords is not even enough to use md5 or sha1 safely as they both are vulnerable to collision attacks. – Johnride May 25 '17 at 19:07
11

I haven't tested this myself, but reading Nginx's source code, it seems to use libc's crypt() function directly. Depending on your OS, you may have a sane crypt() implementation available, either bcrypt or glibc's SHA-256/SHA-512 scheme. It's worth a shot to see if you can use it with Nginx.

  • 3
    I'm on debian wheezy and it works, nginx can use SHA-512 hashes (this is also used for /etc/shadow) through crypt(). According to this thread sha512 is 100 times slower than sha1/ssha1 (44k keys/sec vs. 417.7M keys/sec). But according to this post md5apr1 is the hardest to brute force (2M keys/sec md5apr1 vs. 68M keys/sec sha512). Well, I think I will do as the debian team does: using crypt with sha512. – ahofmann Dec 16 '13 at 8:29
  • 3
    I just tested a hash generated with mkpasswd -m sha-512 On Ubuntu 14.04 and it worked perfectly. So, as @Matt Nordhoff suggests, SHA-512 is supported. – e18r May 30 '15 at 0:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.