Using www-authenticate for user authentication
saucecode.bar
saucecode.bar
There are also other flavours of authentication that can be used in this context, like Digest, supported by all major browsers and only sending hashed passwords (even on plain http connections).
In the most secure configuration of digest auth, the server stores MD5(username:realm:password), and to authenticate, the server sends server_nonce, and the client sends back client_nonce and MD5(MD5(username:realm:password):server_nonce:client_nonce). The nonces are used to avoid a replay attack. The server MD5s its stored hash with server_nonce:client_nonce and checks if it matches against what the client sent.
But if those stored hashes get leaked, an attacker can use them to authenticate. You're in a better position than storing plaintext passwords, because the underlying cleartext probably won't be leaked (they're hashed with MD5, so it's not certain), so your users' credentials can't be used in future credential stuffing attacks, etc. But the attacker still has their credentials on your site.
In the other configurations of digest auth, the server ends up storing plaintext passwords (or reversably-encrypted passwords, which is just as bad).
See also https://en.wikipedia.org/wiki/Digest_access_authentication#D...
Using HTTPS + Basic Auth is far more secure, and (arguably) easier at this point.
HTTPS is a huge waste of electricity.
A more frugal way of securing logins is to use this RFC: https://datatracker.ietf.org/doc/html/rfc2289
Registrations would need additional security but HTTPS with centralized root certificates is NOT one of them.
My point is that storing passwords in a way compatible with using Digest authentication is essentially equivalent to storing your passwords in plain text, at least with respect to your own site’s authentication.
And then you send a server salt/nonce and the browser hashes the plain text password with the salted hash in your database and then with the server salt/nonce.
Still HTTPS solves nothing of that.
I don't even know what Digest is... I'm talking this RFC:
client_nonce?
This is how the RFC works: Hash(Hash(username:password):server_nonce)
What is the difference between Hash1 and Hash2?
Hash(username:password) is what you store in the database != plain text.
Also what is realm?
Yes, the client also generates a nonce that is included in the digest. The full digest (according to RFC 2617) is (assuming qop is used):
request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" nc-value ":" unq(cnonce-value) ":" unq(qop-value) ":" H(A2) ) <">
> What is the difference between Hash1 and Hash2?
Hash1 is the hash algorithm for the authorization digest, so MD5 or maybe SHA256 (although only firefox currently supports that). Hash2 is the hash algorithm (including salting) used on the server to hash the hash of the username password before storing in the database.
> Hash(username:password) is what you store in the database != plain text.
The password isn't plaintext, but if the Hash(username:password) is compromised that gives an attacker enough information to impersonate that user. The attacker can just use that `Hash(username:password)` to compute the digest, they don't need to know the original password.
And who cares if you need a rainbow table?
Ignoring all the other benefits of HTTPS, it means you can securely transfer the password itself to the server, or a deterministic hash of the password which the server hashes again. Not to mention that you can use a stronger hashing algorithm, like bcrypt. There might be other ways to do this, but https is definitely the most practical.
> who cares if you need a rainbow table?
If the passwords are moderately strong and you are using a good hashing algorithm (that is salted), then creating a big enough rainbow table (or brute forcing) is intractable.
If it's an attack you can do after the database is compromised it's not very interesting, and if it's an attack you can do over the wire then you can just limit the number of login attempts per some duration no?
There are numerous ways to accidentally introduce a weakness to 2nd preimage resistance. Using an HMAC is a way to “reset” the entropy of a hash key and eliminate any unwanted source of information leakage.
BUT if you trust it with anything it's a password so that only you can prove that you are you. And then you use server side nonce hashing to ONLY compute that part securely wasting only the required cycles one each end to proove you are you period!
Then, if for some reason you need additional security on some ulterior action, say a payment, you just do the same trick again. That way you save your servers and the electricity grid from encrypting every meaningless cat picture in the world just because you are paranoid.
Electricity is not an energy source, we are going to pay a very high price for it soon. It's the most liquid energy form we have and therefor when oil becomes illiquid (both litteraly and economically because the quality of oil is degrading at a rapid pace) prices in electrons (which have no quality properties that differ) will explode!
Again read the RFC https://datatracker.ietf.org/doc/html/rfc2289, and think about where you want to spend you energy, more customers or less energy for your own kids.
Okay, so your proposal is to never use any private info, anywhere, ever on the internet?
> Again read the RFC
Page 2 of that RFC says
> It does not prevent a network eavesdropper from gaining access to private information and does not provide protection against either "social engineering" or active attacks
How do you propose to prevent MITM attacks? How do you propose to be able to send private data to a server in a way that is readable by the server?
Embrace the chaos, hide in the noise and save energy!
You've reduced your own argument to a non-answer.
Surely you understand that there are different types of "privacy":
- things that only you know (that aren't sent anywhere and maybe even are encrypted at rest)
- things that only a set of trusted parties are supposed to know
The latter is what HTTPS allows you to achieve, alongside making it so that there's no possibility of a "man in the middle", which could not only read the contents of your request, but also alter it (or do the same for the server side response). OTP, TOTP and JWT are lovely for authentication, but they do not address the above concerns, as pointed out by the poster that you're replying to, before discarding your own argument.Suppose that you have no encryption but have the best authentication system in the world. What's to prevent some hacker from setting themselves up in the middle between you and the e-commerce site that you're on and messing with requests however they please, showing both you and the site what they want you to see? You tried to buy an HDD for 50$? They just bought themselves a laptop for 500$.
The fact that there's a very secure bit of information somewhere in the request does not protect you from the rest of JSON being changed to say whatever they want it to (unless you are signing the contents of every request, but at that point you're reinventing HTTPS in some capacity). Or even the fact that they could set themselves up in the middle, presenting themselves as you to the site and presenting themselves as the site to you, albeit with more effort.
Of course, an e-commerce site is a silly example, but what about you receiving a bill that tells you to send money to a different account than you should? What would your banking site look like without encryption? Is your suggestiong for no one to do online banking because "nothing is private", even though we already have HTTPS which addresses this very issue ALONGSIDE various authentication methods?
Totally makes sense...
But for the simple hashing it's an old RFC that I like to quote to HTTPS fools: https://datatracker.ietf.org/doc/html/rfc2289
Way better login than moving your whole site, including cat pictures, to encryption.
Glad that was a temporary state of things.
> logging out is done by simply returning a 401 without www-authenticate header
I did not know that worked!
Stock nginx/apache configurations will basically let the user retry infinitely or show a plain error page after user authentication fails too often, but these pages are configurable and don't need to be handled by the web server itself.
One thing this mechanism doesn't provide is brute force protection through systems like CAPTCHAs.
On every page or widget you ask for authentication for you should have a clear nearby link that says "Forgot your Password?" this link shouldn't be in the standard information display text color (i.e. maybe black or a soft grey) and un-underlined because "it looks slick" - it should be obvious as hell, it's probably one of the best places to make sure of the old "color: blue; text-decoration: underline" styles[1] just so that users that are unfamiliar with your standard link coloration have absolutely no confusion.
I consider myself to generally not be a design oriented person, but I've seen this particular mistake cost so much business over my career that it is a hill I'm willing to die on. "Forgot your password" links need to be clear and constantly accessible - you should push back aggressively against anyone who wants to pop a little paper clip in there with a speech bubble of "It looks like you may be having trouble logging in" or anything else that deviates from those three words. When we're frustrated with a site we all just want to see "Forgot your password?" in blue and know immediately what we need to do - we never want to need to endure your design decisions or technical limitations to get there.
This component needs to be easy.
1. Ubisoft is a great example of this - they've got an extremely javascript laden login page for UPlay and yet "Forgot your password?" is written using that precise three word spell and is in "I'm a link from the 90s" blue - they decided to remove the underlining which is a frequent design decision these days (one I disagree with) but otherwise they're making it as blatant as possible https://account.ubisoft.com/en-US/login There's a bunch of stuff I'd complain about on this page (including the fact that on my browser on a 1080p screen I somehow end up with two different scroll bars) but it knows what's important.
That's why you should also show the information when they cancel the prompt. Users will click the login link (because that's where password recovery is normally located), see a login popup, click close or cancel, and be greeted by a recovery page. No need to fill in fake info that way.
There's also no reason not to link to the recovery page! You could just as easily add a link underneath or next to the big green buttons that say "login" and "register". It all depends on how barren ("clean") you want your front page to be.
I abhor modern authentication systems (Google and Microsoft don't even show the password field next to the username field anymore for fuck's sake, you have to pass some kind of AJAX/Javascript validation logic), that's why I want authentication to return to the browser itself. There's a lot to be fixed regarding browser auth UI, most importantly better password manager integration, but taking auth flow control away from over-eager web designers can solve a lot of usability issues.
Browser auth is actually quite successfully implemented on mobile through U2F. I can click login, tap my thumb on the fingerprint sensor, get directed to a recovery/signup page if my device has no keys for that website or get authenticated automatically. On the desktop side TPMs should become available more often now that Windows 11 requires them (macs already have their own TPM implementation, of course). The quicker websites adopt this flow, the easier auth will become. That said, I've seen webauthn sites that don't ask you to validate your email after signing up, and that's a recipe for disaster, so the system isn't 100% perfect.
As a developer, the browser login popup follows your users' preferences rather than yours. That's also a net positive in my book.
You would have to rewrite HTML5 and handle all HTTP traffic manually to set the Authentication header for every request. OP's trick of HTTP + ancient browser spec for handling basic auth triggers automatic sending of the Auth header for all requests.
> the nice thing about this is that the browser will keep sending the credentials to subsequent requests of the same domain until it receives a 401 status as response.
You don't need to set anything, just send a 401 if you want the browser to stop sending credentials. You don't even need cookies.
There's no button to create a new account or find a forgotten password. There's no reasonable way to logout. It's usable for a site with a trainable user base, like a small club or employees, but I wouldn't expect anything intended for public use to do it. I've experienced one public site that used it for its members only (subscription) content, but I think they've switched to forms and cookies.
> the nice thing about this is that the browser will keep sending the credentials to subsequent requests of the same domain until it receives a 401 status as response.
The logout button can simply redirect to a static page that returns a 401.
The generic HTTP server error screen is merely an implementation detail. It's a result of people using HTTP Basic auth for a quick & dirty login mechanism rather than actually putting effort in.
This protocol combined with modern alternatives (like WebAuthn) should make for excellent accessible authentication mechanisms. It's a shame browser support is so mediocre (for example, password managers + HTTP auth can only work without user interaction) because the browser is perfectly capable of doing everything your usual boilerplate login page does.
As for SSO, the system supports Kerberos authentication, so using this rather than a custom HTTP login flow might actually make your users' lives a lot easier in some cases!
The MITM part is, in my opinion, an unimportant invention of the original reporter. The change was made because the basic auth dialog is part of the browser chrome (i.e. UI not part of web pages). This UI often looks like part of the browser/OS (especially in legacy IE, but modern browsers also show it differently, with the dialog partially obscuring the bookmarks toolbar. You don’t need a MITM attack for this to go wrong, all you need is a rogue ad or something redirecting you to the attacker’s site. Users might think “the dialog is asking me for my Google password, and it’s presented by the Google Chrome browser, so it’s got to be legitimate.”
Basic Auth just sucks. It's hard for users to understand, and everyone stopped using it as soon as cookies became a thing.
As far as I can tell, it doesn't integrate with any sort of platform-level sync, either. My tablet doesn't get my phone's credentials; it has to be independently enrolled.
I'm not entirely sure what the concern is to be honest. If it's tracking, this doesn't provide anything on top of query parameters e.g. ?utm_campaign=
Placing the username and password in the URL results in the same TLS-protected HTTP header as normal basic authentication:
$ curl -v https://user:pass@example.com/page
[...]
> GET /page HTTP/2
> Host: example.com
> authorization: Basic dXNlcjpwYXNz
> user-agent: curl/7.77.0
> accept: */*
>
Even over HTTP, a proxy that intentionally logs the URL accessed would not see the username and password in the initial "GET" line. It would have to go out of its way to extract it from the Authorization header, which is still present regardless of how the basic authentication was initiated.If you meant user agents logging the username and password as part of the history, I suppose you could consider that a bug but it could also be considered a feature. Presumably if you're using a URL of that form your intent is in fact to be able to link or bookmark the URL including the credentials.
And corporate proxies man in the middle everyone, because the entity that controls the proxy also controls the certificate on the computer.
Also, interestingly, the support matrix suggests that Firefox for Android supports Kerberos and NTLM authentication. I guess I never expected Kerberos for websites to show up outside of desktop browsers.
[1]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WW...
The obvious way to improve it would be to offer a way for the browser to load a custom form to authenticate and get the (hashed) credentials to present to the original website in the header. And then you have recreated session cookies in full.
Both BasicAuth and Cookie reception are features included in nearly every browser offering - it's generally how you actually check resource authorization that's the hard part of Auth - the actual technical "Get a cookie from a browser" and "Check the BasicAuth headers" portions are pretty simple - in fact getting a cookie is arguably easier in most cases. Especially since a popular serverside programming language (PHP) has streamlined session handling to the point that most programmers going from it to other serverside languages get confused when there isn't a $_SESSION equivalent that you just inspect with the tap of a button.
You can look at functionality like Apache’s mod_authnz_ldap as an example of built in account management that integrates with HTTP basic auth.
The only difference I can see is that the browser has a native control for one of them, though that control cannot be customised by the site.