20

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 8th 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 of 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?

schroeder
  • 123,438
  • 55
  • 284
  • 319
ahofmann
  • 303
  • 1
  • 2
  • 6
  • 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
  • 3
    Thanks for the answer. The DoS method could be mitigated by throttling, nginx is able to do this with the limit module http://nginx.org/en/docs/http/ngx_http_limit_req_module.html – ahofmann Dec 12 '13 at 17:09
  • 1
    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

1 Answers1

13

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.

Matt Nordhoff
  • 206
  • 2
  • 3
  • 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](https://hashcat.net/forum/thread-2617.html) sha512 is 100 times slower than sha1/ssha1 (44k keys/sec vs. 417.7M keys/sec). But according to [this post](http://www.phillips321.co.uk/2012/05/01/oclhashcat-plus-0-07-vs-0-08-speed-6950-2gb-kubuntu-11-10/) 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 08:29
  • 4
    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 00:59