I probably would never try to implement this on my own website. My login pages don't use JS, so unless the browser did the work for me, it's complexity that I'm never going to understand running on the most crucial page on my site.
Moreover, though, users run so much shit in their browsers. More than half of the logged errors on my site are from user scripts and browser extension content scripts doing lord knows what. They can all just slurp the value out of the DOM, no questions asked. Never mind my CSP, HTTPS, and all of the effort I go to making my server environment secure and safe. The weakest link is not the password getting sent to my servers (over HTTPS), it's the utter free-for-all happening on the page in the first place.
It's really hard to come up with a sane reason why you would ever implement a PAKE with a browser HTTPS application. Probably the best-known use of any PAKE is in Magic Wormhole, where the PAKE passphrase (auto-generated) is a fundamental part of the trust model, and the application itself never touches a browser.
It's a problem with PAKEs that they're kind of neat to think about and play with, so people look for things to stick them onto. They're usually not the answer, which is why you don't see them used all that often, and why they're used almost exclusively in custom protocol settings.
(It doesn't help PAKE adoption that most custom protocols are better served by standard authenticated key exchanges based on real cryptographic secrets, rather than passphrases).
Here's one example where a PAKE would be very helpful.
In Matrix E2EE chat, every user winds up with a ton of different E2EE sessions and thus a ton of different keys that they need to store. (This part of the protocol is unnecessarily complicated IMO, but it's too late to change it now.)
The key to making multi-device support work in practice has been to store an encrypted archive of all the keys for all your sessions, in encrypted form on the server. Where do you get the key for this encryption? It seems the only workable option is to derive it from a passphrase, since the user might choose to log in from a new device (or a new browser) at any moment. So the secret has to live only in the user's head.
But now each user has to remember two passwords: (1) their login password and (2) their encrypted key backup password. Do we really believe that they will pick two totally different, independent passwords??? And if they don't, then in what way are the E2EE keys protected from the server?
So it would be great if we could prevent the server ever learning the login password. For that reason, a few of us random volunteers have been looking at adding SRP or SCRAM or something to Matrix.
I don't understand why you would ever protect an encrypted archive of keys stored serverside with a passphrase authenticated from a password hash stored on the server (which is effectively how a PAKE works).
It sounds like what you want is a password-based KDF, to derive keys clientside for the encrypted bundle.
(SRP is pretty much dead now, for what it's worth).
> It sounds like what you want is a password-based KDF, to derive keys clientside for the encrypted bundle.
The encrypted blob containing E2EE keys is encrypted with a symmetric key that's derived from PBKDF2 on a passphrase.
The problem is that standard password-based authentication exposes the login password to the server every time the user logs in.
So if the user is lazy and uses the same password for both purposes, then the server could very easily derive the key and decrypt the blob that contains all of the E2EE keys.
Even if the user picks slightly different passwords, e.g. "password1" vs "password2", the server has a huge advantage over your standard brute force attacker.
> (SRP is pretty much dead now, for what it's worth).
I am having trouble following the security design here. If the server ever decrypts this data, it doesn't matter how you store the keys. If it doesn't, the encryption keys never need to leave the client.
I think you need to start by very clearly defining the security model you are trying to design, and then start talking about constructions to throw at it.
I don't know what the shrug means, but you shouldn't use SRP in a 2021 design.
The shrug was that it’s weird to call something dead when it never really took off in the first place.
> you shouldn’t use SRP in a 2021 design
Ok I guess I’ll take your word for it. Which PAKE should we use instead? This is the perfect time to change our plans, since we haven’t really built anything yet.
I'm still not clear on what the PAKE is doing here, or what's being decrypted where. The problem with a PAKE between clients and servers, especially if based on the same password as the root secret for your system, is that it depends on storing a password-derived verifier on the server. That's almost never OK!
I think this gets at the root of the confusion. Talking through this has been helpful, so thanks.
So the main thing is that apparently using a PAKE is not sufficient by itself. Not revealing the password at login time only solves part of the problem.
The second requirement is that the PAKE’s “password related string” that it learns and stores must be something that does not reveal (significant information about) the password itself.
I had assumed that that was a baseline “table stakes” kind of requirement for an authentication protocol in the 2020’s, but apparently that’s not part of the definition here(?)
As to your comment about using the same password to create the verifier and the encryption key, I agree it’s not ideal. But in the real world, what practical alternative do we have?
We have password hashing functions that are pretty good at making password cracking impractical. We should use them and trust them to do their job.
As long as the verifier comes from a hash that makes finding preimages prohibitively expensive (ie, a PHF), then it seems like there’s room to work here.
Or if you have better ideas, I would love to hear them. (Not being snarky here - it would actually be good to get input from someone who works on this stuff.)
I'm still not clear on what problem you're trying to solve, but if you have a messaging system with root secret password that's used to protect message confidentiality, you cannot have information about that password stored on servers. The verifier a PAKE uses to check password validity in an augmented PAKE reveals information about the message-protecting password.
Maybe I'm unclear about the application here! But what I'm reading is a proposal in which the deployment of a PAKE could make the system drastically less secure on the whole.
I think you might as well client-side hash it under these circumstances?
Like the "proper" answer is rethink your protocol, have 1 password and make everything not suck.
Minimum (and achievable) job? Client side hash.
Yes it's sh%tty JS crypto in the web case but you have legacy reasons you don't want plaintext even over SSL and you're not going to promise "military grade crypto" to anyone. It's explicable. You can use existing decently reviewed JS libs at least. Any kind of PAKE was gonna be weird JS libraries for web folks anyway.
Yes you're exposed to all the CDNs your UIs use but you were exposed to them anyway.
OK yes tptacek JS crypto is bad and the browser is the worst runtime ever but it's still orders of magnitude less code than needed to make a functional web ui for a chat client, it's pretty bounded, testable and the worst case screwup is not much different than sending your password to the server in plaintext. Which is current state.
The server can store a sha256 of the PBKDF2 output of your client hashing process or whatevs? It's likely to be harder to crack than the key blob you stored on servers already. From a data at rest and in flight standpoint this is at least the same security you get from a PAKE but way easier for everyone to understand. It's one-round, no one needs to think, on server side you can still politely upgrade with zero user interaction. Clients don't have to use fringe crypto supported by one person on github. (Good luck finding a cocoa pod for any kind of PAKE).
It will get weird sending salts to clients if you care about username enumeration, feels like the only way for that not to be stateful in a bad way on your servers is if you derive it from email or login id or something (aka don't actually need to store or send). Not sure how you would resolve that if your UX needs to support multiple login identifiers. That would be hard because you have secret but pre-auth information (relationship between names), and it would require its own sort of thinking.
I have zero knowledge of matrix and so this will probably go down as an embarassing comment. The things I don't know here outweigh the things I do, so this is probably bad advice.
I do want to say, sometimes you just have to go low tech and the dumb thing is the best answer. Sometimes you have to endure raised eyebrows and not doing the sexy thing for community and engineering reasons.
Props for shipping and maintaining a thing that people use and care about. That is hard. Everyone got raised eyebrows but no one got MRs.
Are you sure that's how Matrix E2EE works? In my experience, to access encrypted chats after logging in for the first time I have to verify the new session by performing a synchronous prompt-verify sequence from an existing session, and I don't remember setting any encryption passphrase at all.
What gives? Are we just using different defaults or clients or something?
Disclaimer: I'm not an expert in this stuff, just a 3rd party client developer who is interested in the topic.
AFAIK, there are two ways to validate a new device in Matrix.
It sounds like you're describing the interactive device validation procedure. After that, your two devices trust each other, and the old device can "cross sign" the public key of your new device, so others can trust it too.
Personally for me, even with cross-signing, I was still getting a significant number of messages that failed to decrypt. Usually I think the problem was that one of my devices wasn't around to receive the original version of some key. And for whatever reason, even with cross-signing, it wasn't getting the keys from my other devices. For example, maybe my other devices were offline at the time.
The fix for me was to go the passphrase route. Now, regardless of what device I'm on, the passphrase gets me access to all of my secrets via the encrypted blob on the server.
If we could go back in time and teach users that passwords are only to be entered into browser chrome, and if that used PAKE, we would be in pretty good shape.
HTTP Basic Authentication was a thing in the 90s. Couple that with TLS+PFS and you already have all the benefits of PAKE, plus the more useful benefit of having a third party verify the identify of the web server the first time you visit.
The major reason HTTP Auth failed, despite the primitive crypto, is the bad client side UX.
> PAKE doesn't share the password with thr server.
The server has a password derivative stored. An SRP verifier for instance is computed from the password hash, so if the server is compromised the hacker can immediate impersonate the server or the password can be brute-forced offline.
I believe OPAQUE is the same, just with stronger (slower) password hash functions in the mix.
A server may store the password hashed, but in a password-over-TLS flow the password is received by the server in plaintext. It is only encrypted on the wire (& the network stack).
Look at all the places in a standard authentication flow where the plaintext password is exposed:
- Any TLS-stripping middleboxes on the client's network. (My personal security nightmare is that someone finds a vulnerability in one of those, and hacks them to scrape anything that looks like a password.) BTW, remember when Kazakhstan did this to their entire country?
- Any TLS-terminating load balancer/front-end-server/etc at the server side of the network.
- Potentially between the front-end server and a backend that does the actual authentication, depending on how traffic is passed there.
- Finally, the server that's doing the authentication -- the password will at the very least be exposed in memory there, so anyone who can read its memory (or modify the server code to leak the passwords) can collect passwords in plaintext.
I agree that with the likes of industrial scale MITM (Cloudflare) in the pipe it's not good... but remember Cloudflare also has access to your session tokens, not just your password, so a PAKE might not help without seriously reworking how we do sessions also.
I'm less concerned about corporate level MITM since in those scenarios the MITM already owns the clients. Regardless of protocol, it's a lost cause there.
Of course if you have the server config and database you could impersonate it. However, phishing would be nearly pointless as most phished sites aren't/hadn't been compromised. (Well, pointless in the universe where entering a password into form elements and not the browser chrome isn't common and taught as a faux pas to users.)
Also, as it is you can brute force hashes offline as well. Yes, the original specification has become weak over time, but so have 3des and md5. SRP never was heavily used and as such new versions arent common; it's not inherently a problem with the concept of password-based mutual authentication.
If the server is compromised, of course the attacker can impersonate the server. With an _augmented_ PAKE (which OPAQUE is), the attacker cannot impersonate the client without a brute forcing step.
Password authentication to something running on local network (and therefore can't get a useful TLS cert) is about it, in my experience. Use the PAKE in place of TOFU to trust a self-signed TLS cert in the browser and get rid of cert warnings, since in my understanding PAKE also helps authenticate the server, not just the user.
The issues is that passwords are red data and you want to minimize the number of places red data exists and can be leaked.
Consider the Twitter issue mentioned in the article. Logging inputs is a very common thing and is often important for security auditing later. But if you add it, you need to make sure you're censoring passwords. If you do that wrong, or something around it later changes, you're leaking plaintext passwords to your logs.
And that's just one angle. There's also db compromise. DB snapshot/backup compromise. There's a dozen more dangerous attack surfaces we haven't even thought of yet.
PAKE means that no matter what you do, you can't leak a plaintext password because you don't know it. That's why it's powerful.
PAKE also means one more thing that can break and one more library (actually two libraries, unless you're running Node) that can have serious security issues.
Those are tradeoffs, and the purism of never handling red data doesn't necessarily offset its costs. Especially in a small organization. If you're going to spend N hours on security, what's going to give you the biggest bang for your buck? PAKE would hardly crack my top 20, honestly. Are you confident your deps are updated quickly after CVEs are published? Is your server's kernel up to date? Are you sure your security group configuration is correct right now? Do you have lint rules to protect against XSS issues? PAKE makes a really bad issue slightly less bad, but there's thousands of things that you could be doing that meaningfully prevent issues in the first place.
If 0.5% of your users get a JavaScript exception from the PAKE library, are you confident that you can fix it? What's the cost of those users not being able to log in (and/or churning)?
When it comes to low hanging fruit at most small businesses, handling of plaintext passwords delivered over a secure connection is small potatoes compared to the myriad of other serious security challenges you're likely facing.
Right. SCRAM is only secure if you already have a secure channel - eg if you’ve already done a TLS handshake with certificate auth. A PAKE is secure on its own. However, IMO most people saying they need a PAKE could use SCRAM instead and actually have a chance of understanding what they have deployed.
Moreover, though, users run so much shit in their browsers. More than half of the logged errors on my site are from user scripts and browser extension content scripts doing lord knows what. They can all just slurp the value out of the DOM, no questions asked. Never mind my CSP, HTTPS, and all of the effort I go to making my server environment secure and safe. The weakest link is not the password getting sent to my servers (over HTTPS), it's the utter free-for-all happening on the page in the first place.