Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Bearer tokens are just awful (mjg59.dreamwidth.org)
85 points by HieronymusBosch on April 5, 2022 | hide | past | favorite | 144 comments


Why does the author assume we want to associate a bearer token with hardware at all? When my services issue a JWT, I am issuing a right to talk to my service. If you want to take that token and move it to your phone, neat good for you. If someone steals your laptop and dumps the secret, that's sure as hell not my problem to solve. The application layer is not the appropriate place to apply a mitigation for a user's laptop getting stolen (even if you in theory could).


You're free to assert that it's not your issue to solve, and I'm free to assert that I'm not using your service as a result. It is possible to provide equivalent functionality without it being trivial to exfiltrate authentication tokens to other devices, and I can't see any good reasons for refusing to do so.


Is this a wholehearted departure then from the whole "Simplicity Principle"? Not to be a complete ass, but in your view is there a defensible reason why every single layer of the entire network stack does not guarantee integrity? It would make things more reliable, after all you would still be guaranteed integrity even if TCP is broken! But we don't do that because we acknowledge that maybe we should be solving issues at the poignant location in the stack rather than just haphazardly shoving things in because we need said things in general.

I'm not disagreeing with your underlying point, really. I do agree that authentication is broken in that it fails to provide the actual guarantees we think it does. This is what I was getting at with my point above about issuing a right to talk to my service--that is, in reality, all any practical authentication system can provide today. You simply can't be certain the TPM your service stashed it's keys is secure without forcing attestation (again, problematic). Therefore, as far as your service can assume, your client may have just published the keys for the world to see. This leaves you in no better a theoretical position and it does not solve any of the problems identified with any other auth mechanism purely because it is not fundamentally.


Your expectations might be too high, would you like all applications to monitor if you enter a bad part of town and revoke tokens just in case?


No, I'd like applications to check with me whether I was ok with the state of my user and their device.


I like a good rant as well as the next person, but had some issues with this one.

> What if we have a scenario where a third party authenticates the client (by verifying that they have a valid token issued by their ID provider) and then uses that to issue their own token that's much longer lived?

He might as well be complaining about car keys. Yes, if I leave my car key in the door of my car, bad things will happen. If you issue a long lived bearer token, bad things will happen.

Bearer tokens are credentials. Short lived and limited, but still credentials. You have to take care of credentials!

Use short lived bearer tokens and refresh tokens. Threat model the ramifications of someone stealing the token. If you really higher assurances, look into client bound bearer tokens (DPoP and MTLS in the OAuth world.)

For a common use case (I work for an auth provider, more details in my bio) of browsers or native applications integrating with other applications and APIs, what are other options for verifying a client is authorized to access a resource:

* sessions, probably with cookies. Well known, solid technology. Requires you to either have sticky sessions (so every client request goes to the same server) or a common session store (redis, etc).

* client certificates. If you control all deployment (intranet, employee laptops, etc) can be an option. https://buoyant.io/mtls-guide/ is a good resource if you are doing service to service communication.

* API keys. How do you like your credentials with no internal data structure. Plus, they live forever until you build a rotation system. Yay!

* client bound tokens as mentioned above

I'm not sure what other options are available.

Edit: formatting


> If you issue a long lived bearer token, bad things will happen.

I can issue a short lived bearer token, and another service I don't control can then decide based on that to issue a long lived one and I have no generic way to gain insight into that.


Fair, by using bearer tokens you don't have full control over how they are used by downstream parties.

But that's a bit like saying:

I have a metal key that I only give to trusted people, but someone I trust can make a copy of that key and give me back the original. Therefore I can't trust metal keys.

I guess I'd want to dig in a bit more to understand the use case. Who is deciding to use the other service? Who is accepting the long lived token? (you? If so, why? The issuer? Well then, they made that choice.)


If a metal key that could be duplicated was sufficient for someone to gain access to my company's entire source repository, then yes, I'd say that I shouldn't trust a metal key to be sufficient access control. If that was the best available then I might grudgingly accept it, but in the analogous case here we definitely have something better in the form of hardware-backed asymmetric keys.

Here's an example scenario. One of my users runs Github Desktop and clicks "Sign in". This process involves them performing extra authentication in order to gain access to our enterprise organisation, which is handled by my identity provider. I can hook into that authentication process in order to verify device identity and state, and I can issue a short-lived token. Github will then happily take this short-lived token and provide a long-lived token to the Github Desktop app which will grant access to my organisation's source code without any further authentication, and which is not bound to the device in any way.


> If someone steals your laptop and dumps the secret, that's sure as hell not my problem to solve.

I'm actually curious about the legal situation of stuff like this. Specifically,

1. You issue me a token,

2. that token gets stolen,

3. the stolen token is used to run up a big bill on your service,

4. I refuse to pay that bill (the case being "my laptop was stolen and your service was stolen -- sucks to by both of us, but it's not my obligation to reimburse you for that theft"),

5. You sue me.

What happens? I'm actually genuinely curious, with respect to "stolen services": whose problem is it, really?

What if we insert a new step between 3 and 4 where I tell you the token was stolen, but you choose to accept the token anyways (because eg there wasn't an automated process and the ticket takes a few hours to be resolved)?

(The "you" hear is of course meant to be generic, not Sirened specifically :))


Legally it depends on the service that was stolen. Was this a banking or credit website where some consumer protections might apply or do you have any contractual limitations on cost that may protect you?

But generally you will be liable for the costs incurred from items stolen from your custody. You must then recover those costs from whoever stolen from you


> Was this a banking or credit website where some consumer protections might apply

Let's assume not.

> or do you have any contractual limitations on cost that may protect you?

I guess in this hypothetical case the person whose laptop was stolen cancels the credit card before the charge is made.

> But generally you will be liable for the costs incurred from items stolen from your custody.

Right... but who was the victim of theft here? The service provider or the client of the service provider?

> You must then recover those costs from whoever stolen from you

So... can the service provider sue you to pay for unauthorized use of your account? Or would that get thrown out and then they would have to go sue the person who actually stole the service?

I think it's clear to me that once the service provide gets cash from the person whose laptop was stolen, it's the problem of the person whose laptop was stolen. But if not, is the problem of the service provider?


The short answer is that there are lots of caveats but the service provider will recover the bill from you.

If you refuse to pay and they sue you then they will win and a court will force you to pay, even if it means a sheriff comes to your house and takes your things to sell at a public auction to come up with the money.

You will have to recover from the thief if you want to be made whole. It's possible that if you know who the thief is and can serve them, you can join them to the suit the provider brings against you. Then the court will adjudicate the whole thing together and the thief will directly pay the provider. But that still starts with suing you and action on your part to find and sue the thief.


Interesting. Thanks!


I get the feeling that the author is speaking from the context of corporate zero trust, where they would like certain policies enforced on an endpoint before it is allowed to access a service, and thus transferring the token to an unmanaged device is considered a problem.


Sounds to me like the author is essentially bemoaning a presumed lack of an invalidation mechanism, and thus declares "Bearer tokens considered harmful".


I don't think so. He is bemoaning the lack of mutual authentication. Once the token is handed out the server has no guarantee on later uses it's dealing with the thing it's handed to, and in some ways worse on later uses the user has no guarantee it's dealing with the server than gave it to him.

Bearer tokens are no different to a password in that way. Netflix is currently battling shared passwords, and people regularly have their passwords stolen by a site impersonating the other end.

Invalidation is only useful if you know the bearer token has been stolen or compromised so it doesn't solve them problem. It's no different to demanding your users change their passwords after a leak has been publicised. And besides - it's already possible to keep a registry of invalid tokens, just a it's possible to set a "password must be changed at next login" flag, so invalidation is possible now.

But - the article seems to totally ignore the improvement short lived tokens makes to the situation. If the token only live for 15 minutes, the damage it can do is presumably limited. Still, the point remains - if you could replace a bearer token with something that did mutual authentication on every exchange it be much more secure.

Conceptually, it's not even that difficult. IPSec effectively does it now for every packet sent. You "just" need to build IPSec like mechanisms into every exchange. Actually it's not that hard - with a standardised protocol app developers could use it without much change. But there doesn't appear to be much movement in that direction.

Somewhat harder is "mutually authenticate with what". If the threat model is "someone hacks your computer, and steals the credentials", then it has to be tied to something unhackable that needs to be physically stolen to get any improvement. IPSec doesn't address the problem. Sure, you can authenticate against a certificate, but unless someone has going to the trouble of using a HSM that certificate is really just another long lived bearer token that can be stolen.

That can be fixed. One can imagine a person using a FIDO2 key to authenticate themselves, but all the FIDO2 key does is authorised the TPM in their device to act on their behalf for a while, and the TPM establishes a trust relationship with the servers HSM and somehow tying that all together so every packet exchanges is authenticated with that trust relationship. But now we are talking real complex multilayer protocols.

Such protocols would be far better than what we have now security wise, but it's a huge job. If mjg59 wants that world he would probably be better off doing some social engineering and collecting together a group to write a spec everyone can stomach, not whining about it on the internet.


The device can be snatched along with the FIDO2 key...


Some years ago there were some guys who implemented FIDO2 on an iPhone (Krypt.co, now bought by Akamai).

Sure, people could steal your phone at the same time they steal your laptop. But it's still somewhat less likely, since the phone isn't designed to be plugged in 24/7 in your laptop's USB port, unlike the YubiKey Nano, for example.


Who says authentication needs to stay at the app layer?


I think the article mixes up several different problems. Both cryptographic keys and opaque tokens are "possession factors", i.e. if you have them you can authenticate against a service. Signature-based authentication schemes are mostly used to protect against replay attacks, which are easy to perform with an opaque token as it won't change.

That said you can tie both opaque and cryptographic tokens to additional factors. For example, machine tokens can be tied to specific IP addresses, so an adversary won't be able to use them from a different device. Tying them to other possession factors like TOTP codes would also work, though it's often impractical.

Mobile apps can easily make use of signature-based authentication schemes based on keys stored in a secure enclave, both Apple and Android phones have good support for that. For web apps it's more complicated as there's no way to store keys in an enclave (and many older laptops/computers don't even have TPMs), so you keep them lying around in memory or in the browsers' session/local storage, which of course isn't ideal.


You can actually securely store a key pair inside of indexeddb by setting extractable to false [1]. You can then get a reference to the key and perform your allowed key usages without JS touching the key.

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


So don't set the token to expire after the "heat death of the universe", make the user reauthenticate after an appropriate time for the service being used.


Exactly, all of the reasons bearer tokens might be awful are essentially self inflicted pain. Simple suggestion: don't do that and do it right instead. It's an opaque blob, by design. Which means it could be anything. Including something bearing useful information that you can verify in a sane way.

In our case, we use JWT tokens that contain a few claims, are signed, have an expiration token, etc. Not awful at all. Verifiable information, signed by us with our private key, exchanged over https. That's not information the bearer of the token needs to be aware of but it is something our APIs can trivially verify and use as a basis for authenticating the bearer of the token. Pretty neat mechanism. Nothing wrong with it. Used at scale by world + dog on the internet without a lot of issues.

And before somebody starts ranting about JWTs being awful: same argument. They don't have to be but they can might if you decline to use sane crypto. So, use it properly and you're fine. It's not that hard.


I've deployed JWT a number of times and you're right, it's absolutely fine. The nay-sayers have some of the worst arguments against it I've ever heard and most can be summed up as "if you implement it badly then you can shoot yourself in the foot"... no shit.

I use short-lived JWTs that can be refreshed with another token (revokable on the server and gives a nice way to present "here is where you are logged in" to a user in their profile where they can easily deauth a "Login Device"). By using JWTs everywhere (web and mobile) it means all my endpoints can easily verify the token, grab the user id, and perform the allowed actions for that user's given role (I use roles, but you could also use permissions/claims though that can ballon the JWT quickly depending on how you represent the permissions/claims).

As long as you use a good crypto algo, don't set your JWT's expiration for a long time, and reject JWTs that have an expiration longer than your default expiration, you are golden.


And if I compromise a system that possesses one of those JWTs, I can copy it elsewhere and have access to all the resources that JWT grants me access to. You're not tying it to a specific device, and you're not providing a mechanism to verify the device state when making the access decision.


> And if I compromise a system that possesses one of those JWTs, I can copy it elsewhere and have access to all the resources that JWT grants me access to. You're not tying it to a specific device, and you're not providing a mechanism to verify the device state when making the access decision.

What commonly used authentication method doesn't have this exact same issue? Storing the U/P (which is terrible for other reasons) has the same issue. Using sessions has the same issue. Using API keys has the same issue. What auth method are you using that is somehow tied to the device that can't be trivially spoofed?


Hardware-backed client certificates.


Sure, and you can do that, as long as you realize the corresponding trade-off in usability.

Tell me again how adoption-at-large of PGP encrypted email is coming along?


What trade-off in usability? We don't have standardised mechanisms for sites to provision their own certificates, but if we did then this would be entirely transparent to users in a way that PGP isn't.


That's why we use expiration times. If I was a bank, I would be using very short expiration times and also use second factors. And have a lot of ceremony around releasing our app. And if I cared enough I would indeed add some claims narrowing down the scope of the token to a device, require our user to wear tin foil hats, and what not. Security measures are proportional to the thing they protect. Plenty of banks use both bearer tokens and JWTs. Nothing inherently wrong with that.

If your require these things, do them. If you don't, then don't.


I, as your customer, don't control your expiration time. But I, as your customer, would like to be able to apply my choice of policy to tokens that you issue that grant someone access to my data, because otherwise I don't control access to my data.


In the bank's server, the data might be about you but it does not belong to you. The best you can get is a copy. Regulations control what the bank may publish about you without consequence but the implementation is their purview not yours.


Well, if you are a paying customer, of course we'd be happy to address and accommodate your wants, needs, fears, etc. in exchange for the appropriate fee. Otherwise, sorry, but it just doesn't work that way.


Isn't this issue also present with other popular authentication systems like cookies and client side certificates? If you have a key, you can access the system. If you can copy the key, you can access the system from another location. It's simple as that.

People keep asking to have super smart locks that somehow recognize stolen keys, but how can they?


Approaches that use asymmetric crypto have the advantage that you can use keys that can't be copied - if only the TPM or secure enclave has access to the key, I know that the only copy of the key is on the device.


That approach requires remote attestation (or you can't trust the TPM / secure enclave), which is far too much to ask unless you actually own the device being used to access the service.


100%! As a _user_ I personally would love if I could store all my session authentication info in my device's TPM/SEP for my own safety. I do this with my SSH keys for specifically the reason you suggest—I like that my private keys are non-exportable and so installing a public key on a server is a solid authentication for one device and one device only. This, however, only establishes trust on _my_ end. My SSH servers cannot know or trust that my keys are well guarded because, for all they know, I have a crumby TPM and/or store them unencrypted in my .ssh folder. You cannot make a trust decision based on TPM storage because you have no idea what the TPM actually did (or if aforesaid TPM even _exists_ at all) unless you require remote attestation, which is both non-portable, non-free, and requires you support only users who have a specific variety of CPU.


https://github.com/google/go-attestation is a free implementation of remote attestation that's not associated with any CPU type and will work on anything that has a TPM. But what we want here isn't really remote attestation (which implies attesting to the overall state of the device), it's key attestation (where you verify that the key was generated on a legitimate TPM). But there's still a legitimate privacy concern, in that the attestation is still rooted in an immutable key that would allow anyone who performed key attestation with you to associate your identity with a specific computer.


> key attestation (where you verify that the key was generated on a legitimate TPM)

This is the same problem, just one level further down. The scheme depends on hardware acting against the desires of its owner—whether we're talking about the entire system or just the TPM portion. The privacy concerns are real but not the full extent of the problem.


The credential issuer is (in general) not in a position to make a determination whether the device is trustworthy or not. In an ideal world, I (the person responsible for the security of the device) would be able to ask the issuer to delegate that decision to me (which is what we want for a full ZTA experience), but in the absence of that it's legitimate for the issuer to assume that when the client asserts that a key was generated in hardware that it was telling the truth.


> in the absence of that it's legitimate for the issuer to assume that when the client asserts that a key was generated in hardware that it was telling the truth

You want the credentials to be non-extractable. The client wants to extract the credentials and use them somewhere else. Blind trust in an unsupported assertion from a client with diametrically opposing goals is not much of a security model.


I'm not the service owner. I care about credentials on my clients being hardware backed, and I have enough control over the platform to have reasonable confidence that they'll make a truthful assertion. Clients managed by other people may have different priorities, and should be able to make their own decisions.


If you control the clients then there is no need to assert anything, truthful or otherwise. Go ahead and store the keys in a TPM if you want—the server has no reason to know or care about that. This does not require any key attestation.


You're the one who claimed this approach required remote attestation, not me?


If the service wants to make sure the keys can't be copied then it will need remote attestation for either the whole system or just the TPM (what you called "key attestation") to ensure that the client isn't cheating. If it's only the client that doesn't want the keys to be copied they have any number of options for that and no attestation is needed. I assumed your article was promoting the former as the latter really isn't interesting at all.


That’s why you use platform that already solved IP address and other client fingerprinting. If you are really paranoid - you setup alert policies when users are exfiltrating suspicious amount of info.


IP fingerprinting is unhelpful - the user experience for mobile devices becomes terrible. Any other client fingerprinting is easily duplicated.


Seems like this could be bearable (badum-bum-psh) if it was only enforced during a token refresh (as opposed to every request), even on mobile.


> user experience for mobile devices becomes terrible

Cant have Your cake and eat it too

> client fingerprinting is easily duplicated.

Far from it.


> Cant have Your cake and eat it too

Or we could just use credentials that can be tied to the hardware, and then we have stronger security assertions than tying to IP, and without any degraded user experience.


What is this protocol called and who supports it?


The absence of support for a stronger solution is an argument for improving support for a stronger solution, not an argument against criticising the existing solution.


Was genuinely serious

AFAIK iOS provides hardware keys for fingerprinting


A big limitation is forced early expiration. If you need to do that then you end up needing to share expiration information and therefore need to share something that might as well be a password hash.

So for example it's not great to use instead of a session key. You could design a system where you have, say, 6 API endpoints and instead of the API endpoints needing access to the authentication db, you use bearer tokens from a single sign on to grant access to the API.

That works great until Bob realizes that Eve has got access to his password and hits a password reset to force Eve out the system.

But with bearer tokens, Eve still has access until those tokens expire.

You could add a check for expiration against the calls, but then we're back to session keys being more straightforward because we're back to having some central information (has Bob's token expired) that needs propagation to the different services.

You could have extremely short expiration but then you're back to having to round-trip to re-authenticate often (or in an auto-refresh situation, one where you're back to checking for expiration yet again).

I think bearer tokens work best for internal proxies / APIs to avoid hitting the data store, they aren't a great replacement for session keys.



Long-time fan of joepie. Worth a follow.


I would accept this argument if I had ever in my career run across a case where somebody discovered that their token was stolen and reported that within an hour.

I grant that this can happen at scale, e.g. Dropbox, or for sensitive systems that give mutating access to financial instruments, but for the _vast_ majority of businesses, this is a completely hypothetical problem.


> You could have extremely short expiration but then you're back to having to round-trip to re-authenticate often (or in an auto-refresh situation, one where you're back to checking for expiration yet again).

GraphQL clients like Apollo can solve this by re-authenticating transparently on error and reissuing the same request.


This is a common problem in enterprise single-sign-on systems.

The issue is: If the user presses the 'log out' button, you want it to take effect within a few seconds. But if logouts are simply a timestamped record expiring, they'd have to expire within seconds, and that would basically mean re-authenticating on every single request.

And at the same time, some webapps have shitty re-authentication flows (like discarding any unsaved work-in-progress and kicking the user back to the homepage) and they're only usable with a re-authentication periods measured in days.


It's tradeoff. If you require tokens to be invalidated instantly, there's no way around the notion of doing some kind of lookup when you are validating the tokens. It could be as simple as having a database/memory store somewhere with invalidated tokens or all the still valid tokens. You might cache those for a few seconds so the performance overhead would be pretty minor. You can make this as strict/complicated/slow as you need it to be. It's up to the validating party to decide just how strict they want to be.

But mostly, the device simply deleting the tokens when the user clicks logout is good enough though. Logout does not protect against mitm attacks of course. But that's not what logout is about. And if you have attacks like that going on, the user clicking logout or not does not matter anyway because you can't trust anything they do since you can no longer tell them apart from whomever is attacking. All a logout signals is the user throwing away their tokens (and probably a lot of other local state).

Which is why world + dog uses either tokens that never expire or tokens with expiration times that are pretty long. In our case we use access tokens and refresh tokens. The access tokens are refreshed regularly and the refresh tokens expire after a few months. So, the only users that we force through repeated login procedures are those that don't regularly use our app. Anything more would be annoying. And yes, if their devices get hacked, those users have would have an issue. That's the tradeoff. The user using a token they just threw away is not a real problem because they wouldn't. The user's tokens getting stolen is a different problem. That's why having the tokens expire eventually is a good thing.

Long expiration times are not appropriate if you are a bank for obvious reasons. So, they tend to use expiration times measured in minutes typically and use additional authentication around sensitive transactions.


> But mostly, the device simply deleting the tokens when the user clicks logout is good enough though.

The issue with "simply deleting the tokens" is that this offers no way to force another device to log out. You can only log out the device you're using. If you were to lose your laptop, for example, there is no way to go into your account settings and force the laptop to delete its login tokens, hopefully before an adversary can gain access to them—you need some way of invalidating them on the server.

> If you require tokens to be invalidated instantly, there's no way around the notion of doing some kind of lookup when you are validating the tokens.

If you're okay with invalidating all tokens together then you can avoid storing lists of valid or invalid tokens by tying them to some part of the account state such as a token generation counter or timestamp. The tokens would only be valid so long as that state remains unchanged. Logging out would then consist only of updating that one field in the account.


The problem is that you don't have control over what third parties are doing here. You may have control over the policies associated with tokens issued by your identity provider, but how do you audit the policies that third party services are applying to their tokens?


So I have a service using openid and I use google to authenticate the person logging in. I do that, then that's done.

Now I could simply issue a session cookie, or a permament cookie, to the client so we never have to use google again. Or I could make it so that cookie lasts 10 minutes before reauthentication. I can use a refresh token which means they don't need to reauthenticate but if google expires the connection (disabled user etc), I expire mine.

Either way, that's my decision as the person running my site, and it's the clients decision as the person running the client to decide whether to send the blob, or to share that blob with other clients. The only information I know is that somebody authenticated with google at a specific time and I had proof of that, I have no control over what happens to that blob.

Google has nothing to do with what I or the client do with the information.

You're right that I can't audit the third party (google, microsoft, etc), but I don't pretend I can. Google could simply change their password checking to "if (true)", that's google's business. If I'm worried about the third party authenticator then I shouldn't use it, and I should roll my own.

(There was an early Tom Scott video imagining a world where google just says "yes" to passwords[0])

I have an internal read-only blog site using our corporate openid service to ensure that someone accesses the site. Once they authenticate, I allow them access for 30 days before forcing a reauthentication, because it's low risk. OK if they log in from a compromised machine than a hacker gets to read some internal information, its very low risk.

I've also got a site where you can make major changes. You have to reauthenticate far more frequently to make those changes (every 30 minutes). It's a matter of risk.

[0] https://www.youtube.com/watch?v=y4GB_NDU43Q


I, as the company paying for your service, have no direct ability to influence the policy that you apply to the tokens you issue. If you start issuing tokens that are good for decades, I have no trivial mechanism to detect that.


> I, as the company paying for your service, have no direct ability to influence the policy that you apply to the tokens you issue

a) why would you want that burden b) you're never gonna get it


Ask before you spend the money, stick it in the contract. If you don't like the answer don't sign the contract.


There's no universe where a typical tiny customer is going to be able to impose policy on a large vendor, and there's just not that many vendors in this space. So, yes, I could go with "We're not going to use Github or Gitlab or any similar vendor because they don't meet our needs in this respect" but then I'm probably going to spend a bunch of time explaining to my board why we're reimplementing issue tracking and CI and that's likely to be some rough chuckles.


Either github's systems are good enough for you to use, or they aren't.

If they aren't, you need to find or implement something that is good enough.


That is, in fact, what I'm trying to do - this is the explanation for why I'm doing so.


I don't understand the argument here, if you're not issuing the tokens then they're not your responsibility.

Can you give a more fleshed out example, why should you audit third party services?


Hypothetical: I have a Github Enterprise org. Users log in via my identity provider to gain access. Github then issues a long-lived oauth token to the Github Desktop app. An attacker compromises a user's laptop and copies that oauth token. That attacker now has access to all my private repos until I notice and revoke it.


So you're worried that a very short lived compromise of a SSI / federated auth layer can lead to long-lived compromises of everything it grants access to because a short time can be used to generate long-lived auth to third parties?

That's a legitimate concern, any compromise of the SSI needs a complete refresh of anything it's touched, including refreshing all API keys, keyrings, etc.

Hopefully as the ecosystem matures it'll be easier to en-masse mark an account as compromised and have that status propagate and trigger resets of affected credentials.

A similar threat is insider threat, (probably actually a greater threat) where someone leaving a company could generate tokens which grant them access for long after they've gone.

If reason about how that's typically managed (disabling their upstream accounts) that gives insight into how to deal with your initial concern, it should be managed in the same way.


No, I'm worried that if someone has temporary access to a machine that has one of these long-lived tokens, they may continue to have access to anything that that long-lived token grants access to.


But then there's no third party in that scenario, that's down to whoever was issuing those tokens and is part of securing their service.


I control my laptops. I control the policy for my identity provider. The service that hosts my source code is a third party, and defines their own policy which may not match mine.


That's github's service, before choosing to use it you should look at these policies (who and how github enterprise trust tokens) and see if it matches your needs.

If you were running the service, then the power to trust those tokens is with you.


You're a 5-person startup. How do you verify that all of Github's token issuance policies align with your needs?


Don't. Run your own. It's a cost of business, you can either rely on the standard terms of your suppliers, or you can supply your own, it's far easier than the vast majority of industries.

Git especially is a federated system that has no need for things like github.


Or we could invent better solutions where we didn't need to depend on policies imposed by vendors? The value that Github provides isn't around their git hosting, it's all the integrated features. Reimplementing that isn't going to be trivial - there's a reason so many people use hosted Git rather than doing it themselves.


> In theory you could just hand someone a randomly generated blob, but then you'd need to keep track of which blobs you've issued and when they should be expired and who they correspond to

Is this so difficult?


It is surprisingly difficult in desirable cases, for example if you want your backend architecture to be spread across several sites and with no single point of failure.

If the client starts using the token immediately, propagating that token to all servers before the first use is a harsh requirement.


These are just sessions (e.g. session cookies). The arguments against using database-stored sessions are generally brought up in the context of microservices or decentralized systems where that service/machine that keeps track of sessions becomes a bottleneck/single point of failure for a much larger system.


Session tokens are easy to shard / partition to any number of machines. Just use a random identifier like a GUID. Allocate IDs to machines using either the prefix or any one of the scalable hashing algorithms.


But that's boring technology that has worked for decades. We don't want that. /s


It's strictly more complex without much additional benefit. To have zero-trust random blob tracking you'd still need public key infrastructure, and you'd have a system which is overall more complex and has more ways to break (running out of data storage, network partitions to the database, etc.).

A revocation list would be a smaller, easier-to-distribute dataset if you were going to keep data related to specific tokens around.


I don't see why you need a revocation list - you just need to check access date with the security key. And do a sweep say every couple of hours to delete the security keys that haven't been used.


Revocation is important for SSO and, generally, on corporate systems. When you fire an employee and suspend their systems access, you really don't want a dangling session token to be useable, so you need to support early revocation. The revocation lists will be comparatively very small and so distributing them is less of a challenge. It's mostly just a pain.


If a user decides to logout from certain device, or when you need to log out an active session early


It isn't until it is. And wherever you store it is a juicy target.


Wouldn't you just store it in the same place you're storing the main authentication data (eg. password hashes)?

[edit] I guess that database would get hammered pretty hard on every request, unless you use caching... which might be what you're getting at.


I'm sure tptacek will be along shortly to elaborate.

One would think it gets stored in the database, but man all these hashes are so slow to generate. And which library are we using again for that? bcrypt? scrypt? Seems unnecessarily slow. I bet SHA256 is good 'nuff, and way faster.

Lets just meanwhile call the cloud consultant to move this to a separate service.

Have you heard the good word about AWS Cognito? I heard its web scale.

Nah, too expensive, we should just write our own real quick how hard can it be..


Most sites would be lucky to have this problem. Store your sessions in redis and call it a day.


And more secure would be....what?


Not localstorage. :)

I've seen them in http-only cookies which is sent with every request but not inspectable by js. The server can automatically refresh the token every-so-often transparently without the client even being aware or able to influence it in any way.


When will "until it is" kick in? It has never kicked in for me...


I've worked at a couple of places where the session token lookups were the bulk of database traffic - to the extent that one place had to split it off to its own cluster just to stop it clogging everything up.


I like bearer tokens, but the author's terminology makes it sound like they're not thinking about them from an appropriate perspective.

My preferred way to think about tokens is a form of inter-process communication. In a scenario like 'view this document requires authorisation', the token is a way for the the 'decide whether to authorise' process to communicate some data to the 'view the document' process (that data being 'document-viewing is authorised').

Statements like 'bearer tokens allow hackers to impersonate a user' isn't congruent with what tokens are, or what they're for; in particular, tokens have no concept of "user", "logged in", "authentication", etc. They simply communicate data from one system to another.

The author's complains would be better phrased like "Caching authorisation results is vulnerable to time-of-check-to-time-of-use problems"; that's true regardless of the underlying technology.

Finally, I also consider tokens to be a 'last resort'. From a capability perspective, unauthorised clients should be unable to say what they want; for example, we can restrict access to a document by making its access URL secret and unguessable (we should also allow fresh URLs to be generated, and old ones to be revoked/deleted). That's (a) safer than telling everyone where the document is then having to decide which requests to allow/forbid, and (b) easier to use and integrate into other systems (since it's just a URL; no cookies, "are you a robot?" captchas, etc.).

If we're faced with an action that can't be made secret on its own (like gating it behind an unguessable URL), then we can make it secret by requiring an extra "dummy" parameter; AKA a 'token'.

Note that this is the complete opposite of what the author seems to be describing, which is:

- Reaching for tokens first (rather than as a last resort)

- Having them represent "data" which isn't related to the actions being performed (e.g. "this is person X", rather than "document Y is readable")

- Using this one token to access everything, rather than using fine-grained action-specific authorisation


> one of the core ideas of Zero Trust (that we verify that the client is in a trustworthy state on every access)

A server verifying that a client device is "trustworthy" sounds horribly DRM-esque.


So logically, that's a lacking thesis. And, in fact, an intentionally misleading one.

That said, I'm a big proponent of zero trust.

My real question from this, though, is who actually does zero trust right? I'd really like to know. I would love to work there and prove it works. Ping me if you do that, please.


So what is the option, actually? TEEs and TPMs which the end-user and device owner/operator/admim have zero control or insight into (or is this also under the scope of the "local enclave"?)

OP doesn't propose any in their opinion better alternatives. I'd argue for (roughly, on the move) client-side keys and cryptographic signing (mutual certs basically) and issuing session certs which could be counter-signed, with a short lifetime, but it sounds like they'd be against that too.

Under ZT, how precisely is one to confidently verify local state otherwise? There's a lot of value in the ZT paper and movement, but this particular aspect is both spooky and confounding.


Mutual certs get you closer, but the missing component is device state validation. I probably don't want to share my understanding of device state with a third party (it might include things like which apps are installed on a device, and sharing that with a third party is extremely not cool), and I probably don't want to share my policy (if they get popped then an attacker is going to be able to figure out what I'm looking for), so I need a mechanism where the third party can call out to me with proof of the client identity and I can then compare that against my policy and give an answer back. And we don't have a good way to do that yet.


I agree with OP. The security model is similar to kerberos tickets or ntlm hashes.

Revokable Private key authorizarion is the best way to go imho. I don't mean at the transport layer but at the HTTP/app layer. This should replace not just bearer tokens but authentication cookies as well. Each connection is authenticated by the final server.

Hopefully you can store the private key on fido or tpm as well to make theft harder, forcing attackers to maintain persitent compromise of your host.


This is solved by mechanisms such as DPoP.

https://datatracker.ietf.org/doc/html/draft-ietf-oauth-dpop


Is there a difference between that token and a password? Yes, the token is bigger and created by somebody else, yet for all practical means it walks like a password and quacks like a password...


Isn't the fundamental difference that a password needs checking against a stored per-user value such as password hash and therefore needs a database lookup, while a token can be validated through just the cryptographic signature and therefore avoids hitting the central database?


Yes but then you add revocation and you are back at a centrally stored database to check against.


That's correct.

There are scenarios where it still makes sense.

It's plausible that it would more efficient for some high traffic services to push (the somewhat rare) revocation notices out to endpoints as still being more efficient.

For example imagine a whatsapp clone. People send thousands (probably tens of thousands) more messages than they issue password/auth resets.

Having the incoming message endpoint maintain a cache of recently expired tokens would let you set a reasonably long (e.g. 24 hr) token expiry. You could have the app re-auth in the background on start-up and/or when it detects the expiration window is closing, while incoming messages avoid hitting the central DB for auth.

Maintaining a cache of expired tokens pushed to endpoints would be vast orders of magnitude smaller than maintaining a cache of all session keys.

I don't know for sure though, perhaps central session caches are just more practical and secure anyway for these kind of end-user endpoints.

In some ways this is similar to the Certificate Revocation List handles certs. There are certificate revocation notices that are used instead of needing to check centrally the validity of all certificates.

That said, the CRL has essentially been deprecated in preference of a lookup model.


Actually I never thought about this problem this way, but it seems like in an abstract way the difference between the password and the revocation lists is that of the size of the set:

What is larger, the set of all passwords, or the set of all revoked users?

In most cases the set of all revoked users would be multiple orders of magnitude smaller than the set of of all passwords.

Thanks for writing this message, it made it click for me for some reason.


Then in this scenario it means you will trust the clients to honor the list of bad tokens is it not? Is this not the whole reason bearer authentication is insecure? Either you need to check in the server against a database or you need to trust your clients that they checked against the database..


I didn't think about this, nice feature, very useful in a very distributed system. From the end user (human) perspective on the other hand, it will be stored in a password manager and will need authorization calls and and and - so the only improvement I see is that you can't use "123456" as root account credentials anymore.


I don't think a user should be able to tell the difference. The initial handshake would still use something like passwords or API keys to authenticate the user.

The difference is post-login, where authentication can return for example a 'session key' or can return a JWT or other token that can then be used to say, "I've logged in, I'm xnorswap and I'm allowed in the system until 202204051200Z. I'm allowed access to view users and create reports".


Post login scenario which can happen also after a password authentication :) I mean it already happens, in places... (but your point about distributed heavy duty systems still stands, to keep in mind)


I don't understand. Even if you had a cryptographic challenge mechanism to be verified by specialized hardware in the client, if I control the client then I must be able to "poke around in the API" from it anyway. I think your best bet to prevent this is to to detect abnormal client behaviour and block it.


I don’t get this article. How are you supposed to validate hardware? There’s no API for that. You can bind session to IP but that wouldn’t work for modern mobile connections.

Ideally hardware should have protected private key with manufacturer signature. And API to sign something. Then you can bind session to hardware. But that’s not available today.


You don't verify the hardware directly. You provide a mechanism for client certificate validation (I issue the certs, I can assert that they're tied to hardware), and you provide a callback for validating device state (I define the validation policy, I compare that against the data that I have and say yes or no). It's not about services taking responsibility for this themselves, it's about providing mechanisms for customers to have their own policies enforced.


You are talking about SGX-style TEEs, is that correct? Effectively putting hardware manufacturers as ultimate issuers with corresponding ultimate authority (ie spoofing, revocation, tracking)

Or if not, how would you envision it?


> How are you supposed to validate hardware?

Ah, you’ve discovered the zero trust trap. Don’t worry, advocates will be happy to sell you an ultra expensive security option that breaks more often than it works.


It would be nice to see some alternatives, "it's awful" isn't very constructive. From my experience JWTs significantly simplified development: simple model, easy to understand, standardised, easy to "debug". Show me something that can compete.


It’s also not supposed to be the last stop in your security model - it’s supposed to be the first.


I legitimately don't get the point with all of this.

At the end of the day it's stored the same way on the client side. For any large service you need to have a database call anyway.

Why is there so much written about effectively the same strategy?


Or you can put device/or ip related info baked into the token. That way when the user device or ip changes, you can invalidate the token.


Device info is spoofable, and tying it to IP means the phone experience is just awful.


For sure, but then the user assume they know what they are doing. It is to prevent cookie hijacking.


> Or you can put device/or ip related info baked into the token. That way when the user device or ip changes, you can invalidate the token.

yeah, I always wondered why there isn't a standard field in the JWT containing a fingerprint/hash of the client's machine/browser/etc.


How would that be verified? Any information the client sends to the server can be spoofed by another fake client. The stuff which can't be spoofed (say introduced by the network - IP address etc) can changed for legitimate clients (roaming between wifi and 4g for example)

Unless you use something like a "trusted" hardware module the client has no access too (which is mentioned in the article), but the article is still concerned with compromised machines.


> How would that be verified? Any information the client sends to the server can be spoofed by another fake client.

I'm obviously not understanding how bearer tokens work (another user downthread also contends that fingerprint will work, so I'm pretty certain at this point that I have the wrong mental model).

My understanding is as follows:

1. Client logs into gmail/google/facebook/wherever, and gets a signed token-generating-token.

2. Client goes to legit SiteA. SiteA has no access to the token-generating-token granted in #1 above.

3. SiteA pops up "continue with google/fb/etc" and user clicks "continue", at which point google/fb/etc gets a request for a new token using the TGT to authenticate the user.

4. The final-token is returned to the client, and can be sent to SiteA by the client as proof of identity.

5. SiteA can verify final-token with google/fb/etc.

My question is, why can't the token-generating-token (TGT) embed the hashed fingerprint[1], which is generated by the issuing server, and will never be seen by SiteA?

The final-token can use that hash as added entropy into the salt used for the key that signs final-token, because the issuing server will have the fingerprint-hash that allows it to check the signature of any final-token relayed to it.

[1] Browser-fingerprinting may not be totally unique, but it should be good enough (so, you don't include the IP, but the issuing server can figure out what country it is and use that instead.)


The desire is a hash that doesn't change on a frequent basis, as that's a bad workflow (frequent reauthentication), but one which can't be knowingly cloned

The threat is someone with momentary access to the client machine (either in person or via another exploit) can clone the data.

The server has many things to use for a browser hash, including some stuff that doesn't change very often (you would have to exclude things like screen resolution if you didn't want to reauthenticate your laptop everytime you unplug from a dock for example), but they are all based on information sent by the browser, and thus can be cloned by a process running on the client's machine (even including any Elastic Curve magic ciphers which would be pullable from memory)

The only things that couldn't be cloned would be things not sent by the machine, but instead generated by the network -- IP address etc (network spoofing being a completely different attack, although quite easy to do from a coffee shop)

However using that data would be awful as a workflow as many people will change IP address on a frequent basis

The problem is that with many services, the compromise of a client machine can get a token that never expires. The solution is for the service to require reauthentication periodically.


that's not how it works. the step 4 should be more like: the continue button forwards the client with temporary code (usually in query string), that can be used to request token, with combination of additional secret token (that should remain private/secret), by backend application.

the client never sees the final token, unless the SiteA returns the token to the client, or the exchange of the code happens on the client side. in both cases these are the definitions of incorrect implementation, as the exchange should take place in the backend.

in most implementation you can/should send additional parameters like `nonce` or `state`, which can/should be used to protect against reply/forgery attacks.


Nonce always raises an eyebrow -- In the UK it's a term for child-sex offender ("not on normal courtyard exercise")


Here it means "number used once". Jargon is context-sensitive that way—and we're discussing cryptography, not the UK's legal system.


I also wonder how feasible would be to use TPM. Is it even supported for use from web applications? I'm also don't aware about similar hardware solutions for mobile devices.

Another thing, it's mentioned that we don't control how tokens are created by some third-party, but still, we can use something like Keycloak with external identity provider and client in this case would use token from our Keycloak. In that case we can ensure that for our purposes token will expire quickly.


I'm not aware of any web APIs for secure key storage. That feels like something that would be of value, but coming up with a way to attest to the key being hardware-backed is hard to do without privacy impact - you need some sort of intrinsic hardware-tied key to validate that, and then anyone you do that validation with can tie a key back to the intrinsic key and associate accounts. The Trusted Computing Group tried to solve this with Privacy CAs, which were supposed to issue certificates for intermediate keys that could be randomly generated. But nobody's stepped up to run one, so we're left with Direct Anonymous Attestation, which it turns out may not be possible with the cryptographic features that TPMs provide.

Overall, hardware-backed identity is probably viable in enterprise scenarios where you don't have the same expectation that company-owned hardware will respect your privacy, and we don't have a great solution for doing it at consumer level, and that probably impairs our ability to offer any sort of browser-level API for it.


If someone's in a position to exfiltrate the JWT, they're almost certainly in a position to extract all the information they'd need to reproduce the fingerprint. It'd be a short term strategy until attacker tooling caught up.


>yeah, I always wondered why there isn't a standard field in the JWT containing a fingerprint/hash of the client's machine/browser/etc.

Good that you brought it up. That's why I still bake my own verification session system.


Advertisers would love such a thing


> Advertisers would love such a thing

Why? It doesn't give them any more info than they already have (the logged-in user!)


It could be used to tie that logged in user to other web sessions that are currently anonymous.


> It could be used to tie that logged in user to other web sessions that are currently anonymous.

If those other sessions are anonymous, why do they have the token?

See, I'm not very experienced in web-dev, and I'm very much aware that I may not know what I am talking about.

I'm just trying to understand how the tracking data in the bearer token will "leak". Can you give me a scenario, like "Client goes to SiteA, is then redirected to login on SiteB which grants the token, and then goes to SiteC which reads the token".


You may have different personas that you want to separate. Ie your identity as a local county representative, your identity with a socialist online forum, your identity as employee, your identity as someone discussing weird sexual kinks.

For all you need to identify but you don not want them to be linkable to each other or your government-issued ID.

This is part of why relying on phone number validation for gatekeeping is an issue. (Try registering at Discord or Twitter via tor. I'll wait)


You can hash all that info, so if the user provide the right info (ip, browser string whatever), then the session key would be reconstructed as true.


<Yawn> Another "JWTs are awful" post that fails to coordinate cookies, browser security policy for cookies, and JWT expiry into the coherent security apparatus that many of us use without problems or fanfare.

The anti-hype against JWTs is unjustified.


I recently learned how to use Bearer tokens with a PHP JWT interface and disagree that they are `just awful` (I'm a FE dev for perspective).

I have a setup of a 24 hour token that holds the necessary information to authenticate the user's requests (like a PHP session really), along with a 30 day refresh token.

My Vue FE detects when a 401 status code is returned (using axios) and attempts to refresh the token. If this fails, the user is redirected to the login page.

It works quite well IMO. This setup lets me authenticate cross domain requests without any trouble. I was previously used to doing everything same domain via standard PHP sessions.


Generally the problem is that if your computer gets stolen (or cookie/localstorage etc), the attacker has access to your account for 24 hours. i.e. until there's a check against a disabled-user-list (in the database).

The progression then becomes to reduce it from 24 hours to say 5 minutes (to reduce the attack window, which may or may not be adequate). It then becomes almost the same as validating the user session on each request (not quite, but you start debating if using jwt is worth it at all).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: