Hacker News new | ask | show | jobs
by 8organicbits 1639 days ago
I wish there was a good way to implement this sort of double hashing in web apps. Doing the extra salted hash client side ensures that the value the server sees is globally unique, even when the user is reusing passwords across sites.

Unfortunately the only way I know how to implement that is to have the server send JS down to the browser that instructs it to perform the hashing. For certain types of compromises server side, the attacker would just modify the JS to get the unhashed password. I'd also need to fall back to pure JS hashing for old browsers (5% users?), so there's a UX concern if I perform lots of rounds.

I kind of wish there was a different password HTML field that could run the client side hashing without JS, so the browser would manage that. Ideally using different UX so the user understands they are using a "safe" password field. The end result would be to deny access to the raw password, which is likely reused on multiple sites.

5 comments

There's little security advantage to doing this other than some obscurity, because a well informed attacker can still implement all the same attacks:

* An attacker with access to the database will know they can reduce the "hashing algorithm" to two sequential hashing algorithms and still bruteforce a series of plaintext passwords to check to see if the hash matches what is in the database.

* An attacker with access to the plaintext network communications or app server can just store and replay the second hash to login

* An attacker with access to the client machine can grab the plaintext password still

Lastpass does this is for end-to-end encryption reasons, where it is useful, but for standard apps I don't think it would be.

Your analysis seems to overlook an important detail in that first bullet point - dictionary attacks are only feasible when the KDF is fast. Authentication servers tend to require the KDF to be fast so they aren't constantly performing a denial of service attack on themselves. What people are looking for is a way to make the combined KDF slow by pushing most of the work to the client side. If this succeeds, you have made dictionary attacks very difficult without making your authentication process a denial of service vector.

The web browser ecosystem makes this a pretty hard task, unfortunately. You need fallbacks that weaken the process to the point where it is basically useless in a lot of cases. But the goal of a client/server split in the KDF is actually quite sensible. The client side does the large amount of work to protect users from dictionary attacks. The server side does a relatively much smaller amount of work to protect itself from being easily exploited if its hashes are exfiltrated when the hashes aren't themselves vulnerable to dictionary attacks.

This is an interesting point. I'd be inclined to ensure that the server side hash is still at least independently expensive enough as would be desirable for plain text, but then using the client side hash to go above and beyond computationally seems reasonable to me.

I would wonder though -- there's obviously a practical limit on user experience for waiting for computation, and is there really fast enough implementations available to the browser within that limit that would foil what a dedicated attacker could compute in proper hardware for a dictionary attack? You'd also have to consider if it's really that expensive to just throw more hardware at a server side hash. I guess it'd depend on the browser, whether the attack is targeted, and how big the attacker's budget is that you're considering.

Either way, if this was the goal and the team considered those factors then still felt it was worth the effort of doing so I would think it seems reasonable, though it's probably not something I'd make standard practice in my own apps.

> is there really fast enough implementations available to the browser

Browsers have pretty good support for surfacing native code SHA family hash functions which you can use to speed up PBKDF2. It's called the Web Crypto API and it's available even in Internet Explorer 11. [1]

If you're willing to drop support for IE11 and 10+ year old phones like the iPhone 4S, then you get access to WebAssembly. With WASM you can get a bunch of custom algorithms to be quite fast. The Argon2 browser WASM library claims to be only about 10x slower than optimized native code. [2]

It's not perfect, but it isn't as bad as it used to be with just pure JavaScript.

--

[1] https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_...

[2] https://github.com/antelle/argon2-browser

Yeah, I can't really justify using this in browsers because their capabilities vary so widely. Logging in shouldn't take 10 minutes on a 5-year-old feature phone.

But I can see using a split KDF for some high-security system where the clients all have a known minimum spec.

> that the server side hash is still at least independently expensive enough

That is useless if a hash of the passphrase is sent by the client. The input space is evenly distributed over all hash values, so a dictionary attack is no better than sending all possible hashes directly (brute force).

A single round of server side hash suffices here.

It does prevent inadvertent logging of passwords, though: no piece of software on the server side will have the user's password in memory at any point. Which does mean the user's actual password (if they're reusing passwords) stays more secure (by "more secure" I mean "has a lower probability of leaking to a malicious actor", not necessarily "has some additional security properties").
Ah yes that's a good point. It can still leak the "password" that's used for authentication so it doesn't protect their account on that service but logs wouldn't leak the original password that might be reused elsewhere so it could protect their account on other services marginally more.
If we add client side hashing, it does nothing to prevent hash replay attacks. Agreed.

However, it prevents the attacker from immediately trying the same raw password on other sites (i.e. credential stuffing). They would need to perform additional offline attack of the first hash. This adds cost to something that would have previously been trivial.

Given that about 65% of users reuse passwords and 76% don't even use a password manager [1], I think that slowing down credential stuffing attacks is important.

Protecting against some attacks is valuable even if you don't protect against all attacks. Layered security.

1. https://services.google.com/fh/files/blogs/google_security_i...

Everything you explain points at no need to do client side hashing: what exact attack vector would be stopped by having it? (The only thing you bring up is reuse of passwords, but then you explain how that would be easily exploited if server was compromised, and it's even easier if client is)

I would imagine most developers unfamiliar with encryption would assume that client hashing is sufficient and not bother with server side hashing which is the only one that ensures privacy in case of compromise on the server side (nothing really stops client side compromise).

I assumed the point would be to store all of the salt values ever used server side and never allow reuse of a salt. That way if the hash is captured but has already been used then it is useless.
WASM will do what you want.

You can certainly have client side JS produce a hash using some other credential as the salt and then encrypt the information server side. What you really lose is the ability to do low cost comparison, because most password hashing is done deterministically. Instead you would need to retrieve the record, decrypt with the server side key, and finally compare.

Use client TLS certificates and let the browser handle credential management, including at-rest encryption. Or use FIDO2 hardware. There are many options available but for probably familiarity reasons the vast majority of users and browsers didn't go down that path, and neither did website owners.
I've only seen client certs used in contexts where an IT department assigns them to employees. Has anyone had success with these on public facing websites?

Extra hardware seem cool, but I've also rarely seen people using them. I'm guessing the added cost is a deterrent.

before the current wave of password managers most people didnt use more than one password. they made it easy enough for people to use. now theyre everywhere. the things you list above are the new oddball ui issues, smooth them out a but amd people will use them too.
I see lots of folks in the tech industry using password managers and using the password manager to create and fill passwords. I've also seen people use password managers to remember the ~1 password they self created and consistently reuse.

I'd like to see more password manager use, but changing user behavior is hard. Google suggests <25% of users do so.

https://services.google.com/fh/files/blogs/google_security_i...

But then malware on the user’s machine could catch that password.

There is no 100% solution to this.

Different problems need different solutions. I don't think I've ever seen a solution that solves 100% of all problems. This doesn't stop me from trying to improve security where I see opportunity.
Malware on the user's machine could catch the password in either case.