If you are using HTTPS, you are equally as good as any other login form.
Some have suggested using JavaScript to encrypt passwords before send - but in my opinion, this is generally stupid because it breaks support on browsers without JavaScript, and this doesn't protect you from the server at all because a hacker could just change the JavaScript to send plaintext copies somewhere. You are reliant on the server being a source of truth either way.
Sending the password over HTTPS doesn’t expose the password to passive observers, but it does unnecessarily expose the password to the server.
https://en.m.wikipedia.org/wiki/Password-authenticated_key_a...
Yes - it does - but I am having a hard time thinking that this actually matters in the real world.
I can understand why not sending the password to the server, would be theoretically more secure. However in practice, what hacking attempts does this actually prevent?
If I was a hacker, I can add JavaScript to send plaintext somewhere. If I was a hacker, I could change the login form to stop hashing them client-side and instead send them over to the server for hashing and inspection.
It's theoretically more secure... but against what? Accidental logging? I mean, I guess, but then just set up your logs correctly instead of breaking login for anyone without JavaScript.
In my opinion, client-side hashing is security theater. It sounds impressive, but it doesn't really stop any real-world attacks, and the attacks it does prevent can be prevented using simpler methods. Ironically, the other methods (i.e. making sure your logs are clean) are so much simpler to implement it's probably more secure than trying to build a secure client-hashing implementation in the first place.
Yes, it happens all the time that passwords get logged.
> I mean, I guess, but then just set up your logs correctly instead of breaking login for anyone without JavaScript.
I have no idea what "set up your logs correctly" is supposed to mean but clearly no one's doing it. What is a "clean log" ?
> If I was a hacker, I can add JavaScript to send plaintext somewhere. If I was a hacker, I could change the login form to stop hashing them client-side and instead send them over to the server for hashing and inspection.
This assumes you have full control over the client page. But that's not necessarily (or often? most people don't serve JS from the same code that serves their auth API) the case.
1. The JS could be loaded from a CDN, not the same service that has access to the password. You may have absolutely no control over the JS on the page.
2. Every point between the browser and the password DB is a point where the password is in cleartext. So a compromise of any of those, including any logging paths, is a compromise of the password.
3. I don't think anyone cares about breaking login for users who don't use JS, nor should they.
What's more, ZKP means that if your password database is owned the impact is far less. If you're doing things right for password storage on top of ZKP you can practically make your password db public.
Even if we're talking about a basic client side hashing approach you're significantly improving security, but to be clear, the parent poster is talking about ZKPs, which involve more than that.
As you admitted, passwords get logged "all the time." So the reasonable solution in most cases would be to ensure all applicable logs were clean and not logging passwords, not over-engineer a JavaScript-powered client-side-hashing algorithm. That's like taking a sledgehammer to a nail.
a) Tractable
b) Simple or straightforward
compared to client side hashing is absurd.
Client side hashing is a one time solution forever that exists in one place, requiring no 'cooperation' from other code to be safe. "Cleaning logs", which you still haven't defined at all, is going to be a constant maintenance burden that can break in any place where you log ie: absolutely fucking everywhere by absolutely fucking everyone.
Edit: alright, I saw that you mentioned password reuse in another reply, fair enough, it does help against that.
If it was a consumer-facing web app, it's not like your password is logged in a million different places. It's possibly logged by your web server software (nginx in my case), and it's possibly logged by your web app framework's requests handler. It's not terribly hard to ensure that these points where the password passes through do not have passwords in their logs, or to ensure that said passwords are not logged to begin with.
If it was a massive enterprise system, I would hope that you would use a single-sign-on system with a centralized login page rather than exposing passwords to every web app within it. And then, just ensure that said passwords are not stored in logs. This is what I meant by clean logs - anywhere the password is used, ensure there is no record. How much code and how many layers does a password need to go through?
And yes, maybe client-side hashing does resolve some attacks, but I remain convinced that it is overkill and less protective than it initially seems. And in the future we would move to Zero-Knowledge Proofs but we aren't there yet for general users.
@path("/login")
def login(request):
print("I have a bug, I'll just log the whole request real quick to see wtf is up!", request)
It's actually very hard to ensure that the password doesn't get logged. It requires constant discipline and maintenance. Any bug or change could expose it.> I would hope that you would use a single-sign-on system with a centralized login page rather than exposing passwords to every web app within it
Implementing SSO is a great idea. Not everyone wants to use SSO though. If I were hosting a porn site I wouldn't expect my users to happily "sign in with Facebook". It's also much more work than a basic client hash.
> This is what I meant by clean logs - anywhere the password is used, ensure there is no record. How much code and how many layers does a password need to go through?
You underestimate the places logs can be generated or passwords can be accidentally persisted.
1. Your proxy
2. Crashes, stack traces, segfaults, core dumps, thread dumps, VM snapshots, free'd memory
3. Firewalls, both network and host
4. Audit logs for security, such as via ebpf or other auditing frameworks
5. The application, at any layer. In Python, did you know I can get a reference to the calling function? I've done this for logging purposes before, in fact. So even if your caller is super careful not to pass the password in, saving me from accidentally logging it, I can crawl back up the stack and get it anyway.
6. Your database logs
7. Services/ RPCs that sit between your auth API and your database
And as your business grows and your code changes you'll have to track all of that.
Orrrrrrrrr, you can just hash your password on the client side and significantly reduce the damage of a leak. Or put the extra work in to implement OPAQUE. Or use webauthn, that's cool too.
With public key crypto you can implement a challenge response. Server generates random garbage, send to client, client signs the garbage using priv key, sends it back as a hash that the server can verify using pub key.
Another version of this is with shared secrets instead of public/private, by replacing the signature with simply HMAC(secret, garbage) and keep rest of flow same as above.
Or just use a client side TLS certificate to authenticate instead of or in addition to the username and password.
Maybe, but as a client I can't verify that this happens. So never sending the cleartext password is the only solution.
You have full control over it, as long as you don't embed any third-party maps or crap like ads.
https://developer.mozilla.org/en-US/docs/Web/Security/Subres...
And the nice thing is that browsers already implement that, no need for Javascript. The bad news is that the UX sucks so much that you just can not use, so it's as useful as it not being there.
But digest password authentication protects against nearly none of those errors. On this case, leaking a digest is just as bad as leaking a password.
That's a little confused. PAKE usually still stores a password or hashed password on the server, with the password potentially recoverable by brute force reversing the hash. What it avoids is transmitting a hash over the wire that can be reversed into a password, the way HTTP digest auth allows. The stuff transmitted over the wire by PAKE instead reveals no info about the password.
Most login pages on web sites today send the cleartext password underneath the https encryption layer, so the server sees the password (though hopefully stores it in only in hashed or MAC'd form). That is equivalent to http basic auth sent through https.
I use basic auth + https for my own stuff (where I don't care about styling) and it suffices for most things. Obviously you can escalate from there to 2fa, client certificates with credentials wrapped in hardware tokens, or whatever. I haven't needed that for personal stuff so far.
PAKE is interesting mostly because we have some infrastructure for dealing with passwords already, but passwords in any form are not optimal.
Modern PAKE implementations, like SRP, don't store the plaintext password on the server side, but rather store a "verifier", which is essentially a hashed and salted version of the password. This way the server never sees the actual password, even at the registration phase.
The problem is with the hashing function though. For instance, all the SRP implementations I've seen use fast hash functions like SHA-1, SHA-256 or Blake2b by default. But contrary to folk wisdom (which is unfortunately often repeated here as well), hashing and salting a password is not enough. This is not 2003 anymore, and rainbow tables are not your main threat - your main threat is a cluster of fast GPUs demolishing your hashed passwords at rates that often just start at 1 GH/s.
The best practice nowadays is to use a function which is both computationally expensive and memory-hard such as scrypt or the newer Argon2 (and not PBKDF2!). You could very well do that with a PAKE, but now you run across a nasty UX trade-off: the computationally expensive function would have to be executed on the client side every time the client authenticates. There are WASM implementations of Argon2 out there, so this is probably not a big issue on a beefy PC, but you'll have to aim for the lowest common denominator here, and tune your function for a low-end smartphone.
tl;dr: In practice, with a carefully implemented PAKE, you'll give the attacker a 10-100 times faster hashrate than you would with a plain-text password authentication approach implemented with the same amount of care. In real practice, you'll probably use whatever defaults your library gives you and give often end up with a ridiculously weak hash.
Now, I said this is a trade-off. If you implement PAKE well, you will reduce the resiliency of your stored password hashes against brute force attacks, but this is what you get in return:
* Protection against password sniffing at TLS-terminating proxies
* Protection against hackers taking over your server and stealing user passwords as they login (Online password leak)
* Protection against MITM with a stolen CA key[1]
All of these things are still an issue with clear-text passwords even if you're using TLS. If any of these issues are a concern for you, this means you consider your users' passwords to be significantly more sensitive than the data that flows between your clients and servers, but that could be a valid threat model. In this case PAKE looks like a nice solution.
For everything else, I don't recommend PAKE. It is harder to implement correctly (with library defaults being insecure as I mentioned above), and this is more important than whatever theoretical strengths it has. Cryptographic systems are generally broken because of incorrect implementation rather than theoretical weaknesses in the algorithm.
[1] Not very common, but that did happen in the past: https://en.wikipedia.org/wiki/DigiNotar
But the phishers could do a slight variation. They could create a website that looks very similar to the browser's Basic Auth popup, but implemented in HTML and Javascript. Most people won't notice the difference. Most people don't understand the line of death[1].
[1] https://textslashplain.com/2017/01/14/the-line-of-death/
In the context of the pop-up: a simple pop up can be faked. But what if the browser would flash all the borders (and other stuff outside the line of death) when the real popup is displayed?
I'm not saying any of this is 100% foolproof, just that we should be doing some UI experiments on real people to see what works better.
[1] https://en.wikipedia.org/wiki/EROS_(microkernel)
EROS used capabilities to enforce such rules. If you lack a capability to be a system window, you can't pretend to be one.
I can imagine keyboards having a special “password” key and trying to train people that all passwords start with the password key. I don’t know if this would work, but it can’t be worse than Ctrl-alt-delete.
- If a site is attacked, there is no risk that password material was extracted from application memory — site operator can dump session tokens and safely re-auth users.
I would happily sign up and reuse a password for a website that I didn't trust if it were as secure as described (PAKE + browser built-in login)
Zero Knowledge Proofs would be awesome (something like WebAuthn/FIDO right now?) but I am arguing more in general against client-side hashing methods that are currently usable, mainly JavaScript-based ones.
1. There is, of course, a way to implement it in your web app. I don't know what you mean by "no secure way" ?
> I am arguing more in general against client-side hashing methods that are currently usable, mainly JavaScript-based ones.
Even a trivially implemented client side hashing approach protects against a number of attacks.
How would I implement PAKE login for my users? How would I get every user to log in with PAKE? How would I ensure that my code for PAKE could not be overwritten if a hacker took over part of my server?
It doesn't exist, AFAIK, on a user-facing front at this time in a secure way that a hacker couldn't just change the logic for.
I know nothing of framework support, I don't use frameworks. I'm likely going to contribute some open source code in the near future from my company to simplify things though.
But you could also just have your client do:
salt = sha256("your company name goes here" + username)
password_hash = pbkdf2(plaintext_password, salt)
and get some nice benefits.> How would I ensure that my code for PAKE could not be overwritten if a hacker took over part of my server?
Depends on the server and the level of control. But it'll help in a number of cases. You're assuming the attacker has full control over the web-page's contents (among other things - even if an attacker had the web page's contents CORS means they couldn't send http only cookies to an attacker controlled server), which is a very specific, powerful position to be in.
You are still exposing the password_hash to the server and any compromise there (software or hardware, as described in your link) would still let an attacker grab password_hash, craft a custom client, and send it as if the original client had hashed the plaintext_password to begin with.
The attacker doesn't need to know plaintext_password, just the string you use to authenticate with in order to replay it. The password_hash becomes the new password.
Then due to the salt being on the client, it still opens the password up to rainbow table attacks etc.
That's really the main benefit of this approach - it reduces the impact of password reuse.
From a corporate perspective, with a segmented + well-firewalled architecture, and a lot of surface area for injection vulns, I totally agree with you. The article was priming me to think of a flat, single-box solodev environment, where if someone breaks in, they own everything - which is why I think the original post above us mentioning PAKE is getting a lot of questioning.
If the server issues a different challenge each time, decrypting one response doesn't buy you anything.
Which can safely be assumed to happen whenever the equipment is provided by another party such as an employer. All in the name of security, just not that of the user.
If a zero knowledge (ZK) system combined with HTTP Basic was used, then account entry would come from the browser itself and not a web form that could be intercepted by JavaScript.
Further, a ZK system would help with the silliness of folks using bad algorithms (straight MD-5 / SHA-1) to store passwords, or even storing them in plain-text.
I'm arguing here more against some people who think that using a JavaScript-based system to hash the password entry before sending it to the server is a good idea.
So you're arguing against something nobody is arguing for?
But as the other comment pointed out the current situation with web form login is that password is sent to server so it wouldn’t be worse than the the status quo.
A compromised website that was well designed should not leak your password any more than a client-side hashing implementation. This is because the passwords are hashed in the database. Client-side hashing means that, yes, initially the website is not receiving plaintext passwords, but a few quick code edits to maybe add some logging JavaScript or disable the client-side hashing implementation will fix that.
And credential stuffing? Client-side hashing does absolutely nothing to prevent credential stuffing other than that you may need a GPU to do a lot of hashes quickly. Client-side hashing doesn't make a server handle more or less authentication requests.
Ah yes, "if nobody makes any mistake there's no problem", that's worked so well forever hasn't it?
> Client-side hashing means that, yes, initially the website is not receiving plaintext passwords, but a few quick code edits to maybe add some logging JavaScript or disable the client-side hashing implementation will fix that.
That makes quite literally no sense, did you miss the entire thing and go off with whatever?
The request here is to make the browser's support for HTTP authentication better. The entire point is that there is no "quick code edit" without owning the entire browser at which point you're quite thoroughly owned anyway.
Scenario 2: The ecommerce site has upgraded to SHA512, so cracking isnt an option. But the site is relying on basic auth, so the attacker simply sniffs your password when you auth.
Scenario 3: the ecommerce site is using a secure zero-knowledge auth against a hashed/salted/peppered/whatever credential. They cannot brute force it, and the server never sees your password. They can mess around with the ECOMMERCE_SITE but cannot pivot to any of your other logins.
>If I was a hacker, I can add JavaScript to send plaintext somewhere.
We've just shifted from "quiet, persistent threat" to "hacker announces to the world that he's in". Changing javascript on a prod website is going to trigger alarms.
While I'd like that to be true, it really isn't. There have been loads of card skimming operations injected into production sites which weren't noticed for sometimes months.[0][1][2][3]
[0]: https://blog.malwarebytes.com/hacking-2/2020/03/criminals-ha...
[1]: https://www.wired.com/story/british-airways-hack-details/
[2]: https://www.riskiq.com/blog/external-threat-management/magec...
In the 90s and early aughts it was fashionable for php sites to store passwords hashed, usually some combination of a salt with md5 and later the SHA variants.
For a brief few years there were entire communities on IRC and elsewhere dedicated to making rainbow tables for cracking stolen password hashes.
Often the salt would be common across all passwords, so if you got a database dump it was a gold mine for credentials.
a) Add a static value to the salt ie: your company's name
b) Add the user's email address to the salt
The "right" way would be a zero knowledge proof.
That didn't need client-side hashing to fix it.
Yes, it would. A further improvement to an improvement doesn't take away from the first improvement. Don't let the perfect be the enemy of the good.
Server sends client a salt, client hashes the salt and password and sends back to server.
Implement this as a built-in feature of the web browser, and the browser can show a special icon or symbol to mark that the password will be sent hashed (and later show a warning on password fields sent via plaintext).
1) A different salt each time, meaning the server must know your plaintext password to validate, or 2) The same salt every time, in which case the hash is essentially the password since that's all the attacker has to pass to the server next time.
The point is that a malicious or badly-secured site can't use your password on other websites, because ultimately most people use the same password on many different sites.
Please, stop using those strawman arguments
In any case, though, it seems likely to reduce the impact of a compromise.
Or equally as bad. TLS only protects you from sniffing, not the server seeing your password in cleartext.
I understand how annoying, painful, and disruptive to the user experience it is to have part of your app taken over by browser or OS default widgets and behavior is. It's sheer hell on UX. Yet the custom styling that would make it integrate smoothly would be a godsend for attackers and phishers.
The role that UX - and misuses of UX - play in security is often not considered deeply by highly sophisticated users.
Compared to that, one icon, that is the same as that of the company, is not that threatening.
Not only that, but if you consider a sign in form that wouldn't have a logo, it would be way easier to trick user into putting their credentials in, because the user wouldn't be able to differentiate them. Also OAuth is always branded AFAIK.
Users may also notice discrepancies in the logo, if it was cloned poorly. Though I can't think of a way someone couldn't forge a logo given all the possibilities. Adobe Illustrator can trace images into svg and there's plenty of companies' svg logos just in the google search.
I think the real answer is that allowing this kind of deep and arbitrary styling of interfaces is far more dangerous than it is helpful.
Unless you're somehow able to get everyone to transition at once, never support a non-NFT fallback and, ensure that no sufficiently visually similar logo ever gets registered... which IMO sounds both challenging and like a hacky re-implementation of a trademark system.
The stated (and valid) concern is that malicious actors would use fraudulent branding on those browser auth popups — let’s tell the user we are MSFT or AAPL and steal their password.
One solution is for the branding to consist entirely of NFT assets that can all be tracked to a definitive owner, and use some DNS-based glue (ala DKIM/SPIF for email) to link the NFT to the TLD.
Then your browser can refuse to show the MSFT logo (and show a big red fraud alert page) if the owner of the branding can’t be reliably traced back to Microsoft (owner of the site).
Of course, neither the NFT nor the sig-in-DNS approach actually solves the problem of a visually identical but technically different image (use a slightly different color in a few places, etc.) being used to trick people. I'm not sure what we've gained. The malicious use case would seem like it's not effectively prevented.
I can’t help but think there must be a way to make it work.
I suspect there's a lot of complexity hidden in the perceptual model requirement, though.
As always the only defense is to compare what is being asked for with the FQDN.
Admittedly, there are some simple use cases where HTTP auth is all you need, but it's just way too inflexible, unless you turn it into some mammoth spec that is never going to be as flexible and tempting as managing user identity yourself.
Especially since HTTP auth doesn't actually mean you can stop doing that anyway. You're still handling account creation, password checking, all the abuse / bot detection bits... all you're getting rid of is the sign-on and logout functionality, which is really not that complicated to begin with.
And I think you are missing the point, the goal it's not to standardize logins, it's about making impossible for servers to know my password, hence impossible passwords leaks
That would allow people to reuse strong passwords, and not need passwords managers, because that's what they are doing anyway!
"We" who? Application owners want that, browser vendors want that (their greatest fear is that mobile will eat the web, so they don't want to make the platform less flexible)... and users generally don't mind.
> impossible for servers to know my password, hence impossible passwords leaks
That would require deeper architectural changes to HTTP auth, but is probably a reasonable goal. That said, it's more readily approximated with unique passwords + having a good password manager. The main risk of password leaks is not that they make that particular breach worse (since the attackers can just grab your data), but that passwords are reused too often.
Federated login is another approximation, where the password is only known to your identity provider, not to every identity consumer. It's modestly successful for some lower-value services.
Beside that, if you need a more sophisticated authentication mechanism nowadays your default is to go with something that uses the Oauth protocol: so I guess the next step would be to standardize that protocol and have it integrated as a browser API so that a user doesn't even have to insert a password.
Users don't even see they are being asked to be authenticated, they are either logged in, or told they don't have access.
Works great in corporate world.
The SSPI part is good, it just uses kerberos. But the full set can be downgraded at any time by the server.
Stop passing plain passwords over the wire
this is already solved by httpsAnd with digest auth, the server must have the plain text password already. But sure, maybe there is a third option.
Well, the most common such protocol is TOTP, which still requires the server to store your full password. In that sense it's worse than a naive password exchange, which only requires the server to store your hashed password.
There are other password protocols that require neither transmission nor server retention of the full password, but it seems worth noting that the protocol we actually have didn't bother with that.
I'm not sure what you want to ask.
The problem with TLS client certs, of course, is the fact you need a method of signing CSR's, and the terrible UX modern browsers have for client auth, especially on mobile.
If you just hash the password, the hash becomes the password. You're not solving the problem that way, you're just switching around definitions.
There is an alternative that's supported in most platforms, and that's WebAuthn. Not even a need for a password automatic secure handshakes and with the right protocols, the keys differ per site so they're very hard to spoof through phishing. You can achieve much of the same thing with client TLS certificates, but the UX for that is even worse than the UX for HTTP Basic.
To that one site. But users reuse passwords and if a criminal only has a hash they can't reuse it across sites.
It's not that I don't understand where you're coming from (I once almost started writing such a library a few years back!), but I just can't think of a threat model where this makes sense. That's also what moved me away from working on such a system.
To me, this approach feels like an attempt to recreate software-only U2F, but outside the browser. I don't think client side code can fix these problems. It can make stealing passwords more difficult for criminals if every website uses their own bespoke password processing script, but that'll also add a huge attack surface to your code and it'll be a burden to maintain.
A) Controls the code running the auth API
B) Controls the javascript
As if that's the common attack.
The common attack is that the attacker has a read on the hash, either through injection vulnerabilities or other leaks.
Your attacker, as described, has remote code execution on a server that hosts the auth API and the Javascript in one place. That is a very specific, powerful attacker!
> but I just can't think of a threat model where this makes sense
1. An attacker has CSRF and can trick your code into sending the hash to them. This significantly reduces the harm of that attack.
2. An attacker has an injection vulnerability giving them read access to hashes ie: sql injection, perhaps the most significant and relevant attack to discuss with passwords.
3. An attacker takes advantage of a timing attack, bruteforcing the server and measuring response times to leak its value. They can now only leak the hashed value, which is going to take way longer to leak and doesn't expose their password.
And more!
This defense tackles what are very very arguably the major threats to consider with regards to password security (they're the big ones in OWASP top 10).
> It can make stealing passwords more difficult for criminals if every website uses their own bespoke password processing script, but that'll also add a huge attack surface to your code and it'll be a burden to maintain.
You can significantly reduce harm and attack surface with all of 3 lines in your frontend code.
salt = hash(username + static_salt)
password_hash = pbkdf2(plaintext_password, salt)
it's trivial to implement this.I'll grant you that PAKEs may be more complex to implement today, but even if we talk about a very basic implementation of client side hashing I think there's obvious value.
If you presume the attacker can only read the data transmitted but cannot alter it, your system might work, but I'm not sure in what scenario a hacker can break HTTPS secrecy without also being able to modify the contents of traffic over the wire.
A CSRF vulnerability won't let you send the password to a random host, unless you have full arbitrary code execution (in which case your protections don't make sense either) or if your auth code is unrealistically buggy (letting the attacker embed secrets in a resource somehow).
The database already contains hashes for normal password auth, so I'm not sure why your system would be any better. The password database isn't stored client side, after all, and I hope nobody is still storing passwords in plaintext.
I'm not sure why an attacker would be able to guess the hash from a timing attack, if they can do that then the hashing implementation is very flawed, to the point you just shouldn't be hashing passwords with it.
Your custom salt/hashing system solves password reuse I suppose, but it doesn't add any protections to your website while adding complexity at your cost. For your website, you just changed the way the password looks (which is the hash, not the direct input) at the cost of needing Javascript execution.
In my opinion, your login page would be a lot more secure with a CSP that disallows all scripting, just in case, and uses a simple system that's easy to spot mistakes in, like HTTPS POST or Basic auth.
I don't think that attacker is worth dealing with. At that point you're outside of the security responsibilities of a website and it's the operating systems job to provide security.
> But, breaking basic passwords sent over a secure channel aren't a common attack in general.
Isn't it? Lots of passwords are sent over TLS but SQL injection is still a top 10 vulnerability.
> a hacker can break HTTPS secrecy without also being able to modify the contents of traffic over the wire.
I'm not implying that they can. I'm implying they can read the hashed values after being transmitted to the server.
So attacker in the following positions, at least: 1. Owns your auth endpoint (but not your CDN)
2. Owns your proxy
3. Has read access to your logs and the password is in those logs
4. Has a SQL injection or timing attack against your password auth/ db
> A CSRF vulnerability won't let you send the password to a random host, unless you have full arbitrary code execution
Yeah true, I was thinking about the auth token, not the password.
> I'm not sure why an attacker would be able to guess the hash from a timing attack, if they can do that then the hashing implementation is very flawed,
Timing attacks aren't a property of the hash but of the operations on that hash.
> The database already contains hashes for normal password auth, so I'm not sure why your system would be any better.
Do you mean that the database would be doing server side hashing regardless? That's true (I sure hope). But the attacker will have to brute force a much larger space to recover the plaintext password and the point of doing the client side hashing is to protect other sites if a user reuses their password on those sites.
> Your custom salt/hashing system solves password reuse I suppose
To be clear, that's the point, and I don't think that's small. It's about reducing harm to your users - even if within the scope of your website your user is still vulnerable you are protecting them within the scope of other websites.
I haven't made this argument yet, but I believe it also adds security elsewhere by distributing the cost of your hashing to clients. Your server has to handle N clients, and maybe needs to response in 5ms to each client - so it can spend, say, 3ms on hashing. To keep your tail latencies down you might try to do 1ms of hashing.
But you don't have to worry about your compute if you push it to the client. You can have the client perform, say, 1M rounds of PBKDF2.
So the attacker has two choices.
1. Brute force the client hash, which is 32bytes and really not feasible. That is to say that in a naive brute force they start with 32bytes 0'd out and start counting until they reach your hash - not fun.
2. Brute force the client password, which has a huge number of rounds that you could never get away with on your server. 1M rounds of pbkdf2 is not something you'd want to do on your server but distributed across your clients it's no problem at all - a few hundred milliseconds perhaps. But that's devastating to an attacker trying to recover the plaintext - of course, with some caveats (a relatively weak salt).
I haven't put enough thought into this benefit to claim it, but I may as well throw it out there.
> but it doesn't add any protections to your website while adding complexity at your cost.
It's very little complexity at very little cost. It's a few lines of code that execute at the edge - you pay nothing for those cycles.
> at the cost of needing Javascript execution.
I don't consider this a cost. I think it's totally ridiculous to say that JS execution as a requirement is a "cost" - the vast majority of websites require JS, and there are plenty of good reasons for it (like telling your user their password is too short). If you care so much about JS as a cost, ok, don't do client side hashing.
> In my opinion, your login page would be a lot more secure with a CSP that disallows all scripting, just in case, and uses a simple system that's easy to spot mistakes in, like HTTPS POST or Basic auth.
I disagree. A CSP would be an excellent thing to implement, and everyone should do so. But I don't think that completely denying script execution is a good idea - your users are far more vulnerable to using weak and/or reused passwords than XSS on a site with the minimal scripting necessary to implement this code (no 3rd party packages are required for the code I mentioned).
Your suggestion is basically going back to the days where databases stored plaintext passwords in the database, just that the plaintext happens to be a hash.
Shouldn’t it be a proper challenge/response? Otherwise the hash is barely better than the password.
So, an attempt to solve your question eventually leads to using an asymetric PAKE. But, this is way, way more complex. You'd really have to squint your eyes to believe that the diminishing returns are worth it.
All of which could be easilly standardized
In my experience, the way to logout is to close the browser. Is this standardized anywhere?
> Allow to inject a logo or a tiny bit of customization for branding. The default popup looks too ugly.
I think that this would be nice, but most anyone who wants customization will want to control everything, and wouldn't be a fit for the limits of basic auth.
> Improve the Digest auth to modern crypto standards. Stop passing plain passwords over the wire.
As others have mentioned, TLS helps with this, but I agree that it would be a good idea to hash it anyway.
Have you thought about submitting these improvements to chromium and firefox (as feature requests)?
https://web.archive.org/web/20210422025330if_/http://srp.sta...
SRP allows for TLS without server (or client) certificates. The presence of the verifier on the server provides authentication. No passwords are sent over the wire.
The conventional use for SRP is a replacement for weak passwords (e.g., HTTP Authentication), but what would stop SRP from being used in some cases as a replacement for server certificates even where a website is public (no passwrd required). With SRP, the user becomes the one who is in control of "trust", not a third party certificate issuer or browser vendor. The user decides whether to send a verifier to a website operator.
The stuff we see nowadays is mostly hacks that upgrade legacy systems with things like "the password is actually your-password#token" and "oh yeah, if you use # in your password, it crashes the server ... so don't do that".
Something like a standardized HTTP-based authentication workflow (Basic Auth + maybe parts of the Web AuthN spec) could make things so much easier in regards to maintainability. Then we could finally get rid of stupid workarounds like JWT which weren't designed for this purpose.
There is https://datatracker.ietf.org/doc/html/draft-yusef-httpauth-s... but looks like it had never gained any traction.
And most likely won't, because browser vendors seem to be extremely reluctant to do anything but deprecate all those standard UIs in favor of messed up JS APIs.
The user submit their public key to the server first, then in the feature logins, server will generate a challenge for client to decrypt and respond.
Of course the browser can apply some UX magic at the client end, for example displaying a pop window to allow user to select a public key for the authentication process, etc.
In Firefox you can find them here: Settings -> Privacy & Security -> View Certificates -> Your Certificates
The argument of passing plain password over the wire doesn't make sense: every login form when you submit it passes username and password over the wire! Nobody encrypts the passwords client side.
Oh, sweet summer child
* Add a button to log out. Logout never really worked across browsers with basic auth.
* Allow to inject a logo or a tiny bit of customization for branding. The default popup looks too ugly.
* Improve the Digest auth to modern crypto standards. Stop passing plain passwords over the wire.
That's it. It's not a massive amount of work and it could enable to simplify a lot of the Internet.