I wrote a small webserver which currently uses basic auth over ssl. So far everything works great. Now I want (need) to switch to digest auth. But I can't figure how out to make this work with passwords that are not stored as cleartext in the database? I only have the password digest (generated using bcrypt) of my users' passwords stored. Is http digest auth possible at all?
2 Answers
Was just looking into this just now. First, I read through RFC 2617 - HTTP Authentication: Basic and Digest Access Authentication to get some insight into the specification and see how it can be adapted for a REST API authentication.
Ran into the same question as you did—Does digest authentication mean the server needs to store the user's password in plaintext?
This Stack Overflow answer makes it clear: No. The server doesn't store the plaintext password—it should store the hash of (username|realm|password)
.
That would've been fine except for one thing—the canonical spec only supports using MD5 as the hash function.
Of course you could store both the bcrypt hash and the MD5 hash but doing so only undermines the security of the bcrypt hash effectively rendering it useless (since an attacker can shift his efforts into brute forcing the MD5 hash instead).
So, I took a step back and thought, why not disregard the spec and use bcrypt on both sides as the hash function (bcrypt(username|realm|password)
)?
Well, aside from being purposefully slow, bcrypt has a maximum password length which makes it unsuitable for use as a general digest algorithm.
Whew, by now my head was swimming but I still thought to give it another go. Some of the suggestions were to use TLS with SRP or authenticated encryption, specifically EAX, but I felt that maybe those were taking things just a step too far for a simple Web service.
To put it simply, if you're really bent on doing this you can work around bcrypt's character limitation by using a preliminary hash.
Long story short it seems that you can do:
bcrypt(sha256(username|realm|password))
And use that in place of H(A1)
in a bastardized version of the spec.
The question now becomes—was all that added complexity really worth it? Did we get any added layer of security over Basic auth over HTTPS?
The question now becomes—was all that added complexity really worth it? Did we get any added layer of security over Basic auth over HTTPS?
I can see one, when you use basic auth, your HTTP client sends the Authorization header as a base64(password)
So, if you leave your web browser open, and someone opens the browser web console, he can base64 decode your password.
Whereas, with digest auth, the Authorization header is a md5 hash (and a nonce hash is included to prevent replay attacks)