4

UPDATE: I have concluded my research on this problem and posted a lengthy blog entry explaining my findings: The Unspoken Vulnerability of JWTs. I explain how the big push to use JWTs for local authentication is leaving out one crucial detail: that the signing key must be protected. I also explain that unless you're willing to go to great lengths to protect the keys, you're better off either delegating authentication via Oauth or using traditional session IDs.


I have seen much discussion of the security of JSON Web Tokens -- replay, revocation, data transparency, token-specified alg, token encryption, XSS, CSRF -- but I've not seen any assessment of the risk imposed by relying on a signing key.

If someone breaches a server and acquires a JWT signing key, it seems to me that this person could thereafter use the key to forge unexpired JWTs and secretly gain access. Of course, a server could look up each JWT on each request to confirm its validity, but servers use JWTs exactly so they don't have to do this. The server could confirm the IP address, but that also involves a lookup if the JWT is not to be trusted, and apparently doing this precludes reliable mobile access anyway.

Contrast this with a breach of a server based on session IDs. If this server is hashing passwords, the attacker would have to snag and use a session ID separately for each user before it expires. If the server were only storing hashes of the session IDs, the attacker would have to write to the server to ensure access. Regardless, it seems that the attacker is less advantaged.

I have found one architecture that uses JWTs without this disadvantage. A reverse proxy sits between untrusted clients externally and a backend collection of microservices internally, described here by Nordic APIs. A client acquires an opaque token from an authorization server and uses that token to communicate with the server app for all requests. For each request, the proxy translates the opaque token into a JWT and caches their association. The external world never provides JWTs, limiting the damage wrought by stealing keys (because the proxy goes to the authentication server to confirm the opaque tokens). However, this approach requires dereferencing each client token just as session IDs require per-request dereferencing, eliminating the benefit of JWTs for client requests. In this case, JWTs just allow services to pass user data among themselves without having to fully trust one another -- but I'm still trying to understand the value of the approach.

My concern appears to apply only to the use of JWTs as authentication tokens by untrusted clients. Yet JWTs are used by a number of high-profile APIs, including Google APIs. What am I missing? Maybe server breaches are rarely read-only? Are there ways to mitigate the risk?

Joe Lapp
  • 2,435
  • 3
  • 30
  • 42
  • I thought of a solution that requires the attacker to find the key in RAM, but apparently at the cost of the server having to verify two signatures on each request. Each server of a cluster generates a public/private key pair at launch. It stores the public key in the DB along with a keyID, but the private key vanishes when the server goes down. Each JWT is signed with both a cluster-wide secret (to keep DoS attacks from hitting the DB) and with the key that the JWT identifies by keyID. Servers cache keyIDs and associated public keys. I'm not sure moving exposure to RAM helps much though. – Joe Lapp May 29 '16 at 19:02
  • What is the problem of validating the electronic signature for each request by the server? You should do it. It is a RSA-HMAC signature, simple and very quick to validate. If the key has been stolen, it issues another. If you fear that the key is stolen, use a hardware token (HSM) – pedrofb May 30 '16 at 07:15
  • Depends what you mean by "validate," I think. Do you mean that the server should verify the token signature "for each request"? If that's what you mean but the secret key has been unwittingly stolen, the signature will properly validate even forged tokens. That's the point I'm raising. More likely, I'm not understanding your point. My premis is that no one knows the key is stolen. That's a much worse situation than no one knowing that password and session ID hashes have been stolen. – Joe Lapp May 31 '16 at 02:00
  • Ok, if the secret key has-been unwittingly stolen, you have a serious problem. But I think JWT worth. 1) Mitigate: Change the key periodically. 2) Avoid: Use cryptographic hardware (HSM) to store the secret key. It is cheap enough 3)Prevent: Audit your network infraestructure 4)reduce the impact: it uses different keys according to user groups or access areas – pedrofb May 31 '16 at 07:17
  • I've been brainstorming ways to accomplish (4), but haven't thought of anything that isn't easy for an attacker to work around in the case of JWTs. Regarding the others: (1) Mobile apps require multi-week to multi-month access tokens; (2) large-scale apps these days are deployed on the cloud, so cryptographic hardware isn't an option; (3) an audit won't reveal a stolen key, unless you monitor and try to detect unusual client patterns, but an audit might reveal that JWTs are unsafe. – Joe Lapp May 31 '16 at 11:08
  • In scenarios where secure identity is essential, for example antiphising systems, we use **JWT client-signed**. It uses public key cryptography to provide strong authentication. During registration in the online service the client device creates a key pair. Saves the private key and sends public key to the server. Authentication is tested with the possession of the private key digitally signing a challenge. The private key is generated in the device (iOS -> KeyChain, Android -> KeyStore, Web -> WebCryptographyApi) and can not be exported. – pedrofb May 31 '16 at 11:45
  • 1
    Flag and ask a mod to migrate to http://security.stackexchange.com - you may get answers there. – SilverlightFox May 31 '16 at 15:20
  • I've been reading up on Oauth. Robust implementations of protected resources use the token introspection protocol to verify each token provided by the client, instead of trusting the token itself. Provision exists for allowing the protected resource to cache tokens for short intervals. Resources have to use this protocol in order to allow tokens to be revoked. It seems that serious APIs don't trust even signed tokens. – Joe Lapp Jun 04 '16 at 22:55

2 Answers2

6

I believe you're thinking about this the wrong way. Don't get me wrong, it's great you're considering security, however the way you're approaching it in regards to double checking things server-side, adding additional checks that defeat the objective of stateless sessions, etc, appear to be along a one way street towards the end of your own sanity.

To sum up the two standard approaches:

  • JWTs are sessionless state objects, MAC'd by a secret key held server side.

  • Traditional Session Identifiers are stored either in memory or in a database server-side, and as you say are often hashed to prevent sessions from being hijacked should this data be leaked.

You are also right that write access is often harder for an attacker to achieve. The reason is that database data is often extracted from a target system via a SQL injection exploit. This almost always provides read access to data, but it is harder to insert data using this technique, although not impossible (some exploits actually result in full root access of the target machine being achieved).

If you have a vulnerability that allows access to the key when using JWTs or one that allows database tables to be written to when using session identifiers, then it's game over - you are compromised because your user sessions can be hijacked.

So not more damaging necessarily, it all depends on the depth of the vulnerability.

Double check that the security of your JWT keys align with your risk appetite:

  • Where are they stored?
  • Who has access?
  • Where are backups stored?
  • Are different keys used in pre-production and production deployments of your app?

The ways to mitigate is as good practise dictates with any web app:

  • Regular security assessments and penetration testing.
  • Security code reviews.
  • Intrusion detection and prevention (IDS/IPS).
  • WAF.

These will help you evaluate where your real risks lie. It is pointless concentrating on one particular aspect of your application so much, because this will lead to the neglect of others, which may well be higher risk to your business model. JWTs aren't dangerous and have no more risk than other components of your system necessarily, however if you've chosen to use them you should make sure you're using them appropriately. Whether you are or not comes down to the particular context of your application and that is difficult to assess in a general sense, so I hope my answer guides you in the right direction.

SilverlightFox
  • 32,436
  • 11
  • 76
  • 145
  • 1
    Thanks for the thoughtful response. It's good to hear some confirmation that write-access breaches are less common than read-access breaches. However, I'm not seeing how you've addressed my concern. When a traditional sessions-based server is breached read-only, the attacker job is still hard because all he gets is hashed credentials. When a JWT-based server is breached read-only, the attacker thereafter gets free, unfettered access via the signing key. These breaches happen, so it seems worthy of consideration. – Joe Lapp Jun 01 '16 at 16:05
  • I should clarify that the JWT issuing authority would have to be breached, rather than any client of this authority that happens to also be a server. – Joe Lapp Jun 01 '16 at 16:08
  • 1
    As I tried to allude to, this is quite a broad question. Securing the keys would be down to the individual implementation of the authority. Are you the site or the authority here? Are the keys stored in a DB where they are vulnerable to SQLi, or on the file system where they could be vulnerable to file inclusion or directory traversal? If you want to mitigate the risk in general you could resort to split keys - have half the key in the DB, the second half on the file system. Then an attacker needs two exploits to compromise you. I can't really be more specific without looking at your system. – SilverlightFox Jun 01 '16 at 17:31
  • Yeah, there are many measures one can take for helping to protect keys. Short of using a physical device, an attacker who gets read-only access will get both key halves. In any case, it sounds like you're agreeing with me that this is a concern that needs to be addressed. I'll eventually be deploying to the cloud, where I can't use cryptographic hardware. – Joe Lapp Jun 01 '16 at 21:23
  • I may have missed something from your last comment. If half the key is in the file system of one server and the other half is in the database on another server, that doubles the number of servers that have to be breached. That does indeed mitigate the risk. Thank you for that suggestion! – Joe Lapp Jun 02 '16 at 02:47
  • It mitigates risk, but doesn't change the fact that if they are successful and because you are using JWTs they would end up with full reign and the ability to impersonate any user in your system beginning immediately whereas traditional security forces them to begin crackin', which hopefully takes a long enough time for you to let your users know to change their passwords. – Lo-Tan Jun 11 '16 at 16:13
  • @Lo-Tan: Choosing to use JWT's over server-side session state should be a carefully considered decision, and choosing the former offers less security. For example, sessions cannot be amended server-side meaning logout functionality cannot be properly implemented, and compromised sessions cannot be terminated. If the risk-appetite for your system is low, then you would want to avoid JWT's for these reasons alone, before even considering the security of the private keys. See this too http://phillbarber.blogspot.co.uk/2014/02/client-side-vs-server-side-session.html – SilverlightFox Jun 12 '16 at 07:18
0

When an attacker is able to get hold of the signing key in a JWT based system that means that he is able to get access to the server backend itself. In that case all hope is lost. In comparison to that, when the same attack succeeds in session based systems the attacker would be able to intercept username/password authentication requests to the backend, and/or generate sessions ids himself, and/or change the validation routines required to validate the session ids and/or modify the data to which the session id points. Any security mechanism used to mitigate this works as well for session systems as for JWT systems.

Hans Z.
  • 50,496
  • 12
  • 102
  • 115
  • I think you've stated the assumption that allows people to continue storing keys in convenient places. The OWASP Cryptographic Storage Sheet (https://www.owasp.org/index.php/Cryptographic_Storage_Cheat_Sheet) disagrees, as does Symantec's Internet Security Threat Report 2016, p. 72, (https://www.symantec.com/security-center/threat-report). – Joe Lapp Jun 19 '16 at 22:41
  • I was unable to find statistics for how many breaches are read-only vs read/write. Logically, there are more scenarios where an attacker acquires read access than both read and write, simply by virtue of accounts generally being able to read more than they can write. Additionally, it's easy to read data without being discovered, much harder to write data without risking breaking something. An attacker is going to leverage sensitive data before attempting to patch an application for which he does not have source. It is very much worth guarding against the read access scenario. – Joe Lapp Jun 19 '16 at 22:41