Showing posts with label HOBA. Show all posts
Showing posts with label HOBA. Show all posts

Saturday, January 2, 2021

Storing Asymmetric Keys in Client Storage for Login and Enrollment

Very unlocal storage

I'm genuinely conflicted about whether storing private keys in browser storage is OK all things considered, or really wrong. It certainly feels wrong as hell, and this goes back years. With my HOBA revisited post (using asymmetric keys for login and enrollment), I dusted off my ancient prototype code and used WebCrypto to generate keys, and sign enrollment and login requests. Obviously you don't want to re-enroll keys each time you go to login, so that implies that the private keys need to stored in a place that is accessible to the WebCrypto signing code at the very least. To my knowledge, there is no way to get WebCrypto to keep the keys themselves inaccessible on a permanent basis, so that means they need to be exported, stored by the app, and reimported on the next login attempt.

So what is the implication? That you'll be storing those keys in localStorage or IndexedDB. They could be kept in the clear -- say PEM form -- or even wrapped using a password to encrypt the blob for extra security, in which case it would look much like a normal login form even though the password would not be sent to the server. From everything I can tell this is frowned upon, but strikingly not categorically. OWASP says that it is not good form or somesuch to put sensitive information in client storage. They give some rationale such as XSS attacks, but seem to not be able to work up the courage to say "NO! Don't ever do this!" This leads me to believe that they feel the same yucky feelings like I do, but can't quite bring themselves to have a logical reason to say that it's always bad.

Part of the problem is that if you have XSS problems, you are well and truly fucked; browser based storage is a problem, but everything in your entire existence is a problem too with XSS. So to my mind that says just take that rationale off the table because you would never allow that to be an excuse for shitty practices such as SQL injection attacks: it's just not acceptable, full stop. After that, the rationale to not use browser storage gets murky in a real hurry. As far as I can tell, it reduces down to that yuck factor.

Thinking about this some more, browsers can and do store immense amount of sensitive information. That information is available to javascript code running in the browser sandbox too. That sensitive information is from form fill in helpers from the browser. They collect names, passwords, social security numbers, credit cards, your first dog's name... you name it, it has it. Yet people do not think twice about the browser helping out. All of those things are completely available to javascript and any rogue XSS script it allows to run too. Yet I've not heard anybody sound the klaxons about this, and if anybody has nobody seems to be listening. Which is to say, that ship has long since sailed.

So are they any differences between browser form fill in? Yes, but they are subtle and I'm not sure they really change the attack surface much. Browser helpers do give you the ability to say no, don't fill this in, which is definitely a nice feature and enhances security since not handing it over to the DOM means that the client code won't see it. I think, however, that that is a Chimeric victory: if everybody uses this feature because the browser is good at figuring out what needs to be filled in, then the victory is just nibbling around the edges of the actual security problem.

Now to be certain, I think a situation where the browser stores the keys such that they are not visible to the javascript code where the user is given that choice would be great. What I would visualize is that private keys are stored along with all of the rest of the sensitive data the browsers store, but somehow delivered down to the client js code when the user allows it as with form data. The keys could be encrypted with a secret only the browser knows, or maybe the crypto routines in Webcrypto can take a new key type which is really just a reference to a key rather than the key itself. Which is to say that it's just an implementation detail rather than anything fundamental. This would be ideal to really solve this problem. This would, of course, require changes to the browser and definitely standardization. Which is to say, that it would be a long way off, but it definitely possible.
 
The question that remains is a riff on the Saint Augustinian Bargain: give me better security, but not just yet. That is, should we keep chaste until a better solution comes along, or should we make do in the mean time with a less perfect solution. I guess that given what I can tell with the risks, I put myself into the "just not yet" camp. Passwords over the wire are such a huge problem that almost anything would be better. Given that browsers are already exposing sensitive information including passwords, I'm not sure exactly what the big problem is.  The threats are much worse with passwords given their reuse, it seems to me that it is an incremental gain is completely worth it even if it is not the best long term solution. That is to say, that even if I can manage to steal your private key for a site, that gives me exactly no amplification attack unlike reused passwords.

So in conclusion, yes I totally get the ick factor. But the ick is part and parcel of the entire beast, and not just browser storage mechanisms. What that tells me is that one needs to put this in perspective. As with all security, risk is not an absolute and needs to be viewed in context of the alternatives. The alternative in this case is the additional amplification factor of reused passwords. Since all things are otherwise are fairly equal given browser form fill in code, I think that's pretty significant and a good reason to override the "should not put sensitive information in client storage" recommendations. 






Thursday, May 7, 2020

HOBA Revisted with WebCrypto


The Hoba Meteorite in Namibia


Here's direct link to the running demo which explains in much more detail what's going on than in this post at the HOBA Demo Site

Years ago, I got really pissed off about LinkedIn doing something incredibly stupid, especially for a big company which was storing unsalted passwords on their servers and their subsequent leak. That got me to thinking about getting rid of passwords on the wire if at all possible. This led me to my work on a prototype that used public key crypto to join, login, and enrolling new devices. You can see my original posts  here and here, along with the resulting experimental HOBA RFC (RFC 7486)


I was really excited when I heard about the w3c WebAuthn work hoping it was the successor to our experiment. The reality was when I tried to get WebAuthn to work, it seems regrettably difficult to get up and running, especially without an external signing dongle. It is quite possible that my problems were completely wrapped up with not wanting to require a signing dongle. Chrome doesn't support local key stores at all with WebAuthn, and Firefox does so only by fiddling with about: flags. This is a real shame as I really hoped that WebAuthn could finally bend the curve against passwords being transmitted over the wire which is still a huge problem. Since HOBA was written a lot has changed. WebCrypto now contains solid crypto  functionality accessible to browsers, in comparison to the horrible javascript hackery that I used in the original HOBA RFC. Another thing that has changed for the better is that it is much more common for servers to require an out of band verification (email, sms) to enroll new devices. This was one of my big worries at the time because HOBA required those out of band mechanism for enrolling new devices. Thankfully I don't have to fight that social problem too... lots of somebodies have done that for me in the mean time.

So I decided to give my prototype another look, and see if I could make it into what I had hoped WebAuthn was. Happily, all of the algorithms and backend code are still relevant from my prototype, it was just a matter of replacing the javascript versions of crypto to the more civilized WebCrypto version. Most of the effort was just dusting the cobwebs off the code and stripping it to a bare minimum. In fact, refactoring the crypto code to allow both to run side by side as well as actually writing the WebCrypto driver took all of one day, and a lot of that due to some whacky to/from PEM that was getting me wrapped around the axle which had nothing to do with WebCrypto at all. I've put both versions of code up on GitHub as an example of how this problem space can be attacked in a much more straightforward way if you don't need the added security of crypto dongles. The server code is written in PHP. Sew me. It could trivially be ported to any other language, and the key issue is integration with your own enrollment and login code in the backend so it serves only as an example in the first place. The HOBA-related code is actually very small and pretty easy to understand. The new device enrollment is probably the hardest to understand, but the main takeaway is that out of band verification of ownership of email, phone numbers, etc is pretty common these days so lots of sites have experience with deploying that. When I first wrote my HOBA code, that was much less prevalent.

There are two pretty big open issues. The first is the most straight forward which is whether it should be using a nonce from the server validate freshness instead of time. My guess is that the answer is yes and the implementation of a Digest-like (RFC 7616), as well as the original time based replay protection. The second is how to get enough review to actually believe that it works and doesn't have holes. I've been thinking about writing an internet draft and floating it at IETF but I'm not sure they'd want to take it because the client and server code are definitionally controlled by the same entity so it would mainly be for security review, not protocol agreement across different vendors.

I have created a site to demo the HOBA demo site as well as a Github Repo. Give it a spin and take a look. The demo is stupidly simple: join the site, logout, login to the site. If you want to enroll a new device, either find another or just use another browser and try to login in with your username. The backend will send mail to verify the new login. The only difference with all of this is that there aren't any passwords.