JSON Web Token Security

JSON (JavaScript Object Notation) is a file format that is laid out as structured plaintext, meaning that it is both easily readable by humans, as well as easily parsed by computers. It represents data using a hierarchical data structure that can include key-value pairs and arrays. JSON supports different data types including numbers, strings, Booleans, arrays, and collections of key-value pairs grouped into objects. Despite the use of “JavaScript” in its name, it is in fact language-independent and JSON parsers exist in many different programming languages, leading to its wide adoption.

The snippet below shows an example of how JSON could be used to store data relating to an individual:

{

"firstName": "John",

"lastName": "Smith",

"age": 27,

"address": {

"streetAddress": "21 2nd Street",

"city": "New York",

"state": "NY",

"postalCode": "10021-3100"

},

"spouse": null

}

 

Because of its simple but rigorously defined syntax and structure, one advantage of JSON is that it is easy to validate and parse unambiguously. Although it contains a mix of data and metadata elements, JSON is not (unlike HTML and sometimes XML) generally considered to be a markup language, however. The “markup” elements are used as syntactical bounds to indicate data object types, rather than annotations specifically intended to define style or semantics used in the display of the data.

JSON is highly suited to use in data serialization tasks, in which data is translated into a form that is able to be transferred as a byte-stream between two systems that use incompatible data formats for object storage at either end and is therefore often additionally described as being a lightweight data-interchange format.

JSON has therefore found widespread usage as a lingua franca for data transfer between heterogenous computer systems that may run on different operating systems, application frameworks and programming languages. It has been widely adopted especially within client-server communications such as in JSON-RPC and Asynchronous JavaScript (AJAJ) used in dynamic web pages.

 

What is a token?

 

Tokens in general are a representation, placeholder, or proxy for something else: a simple example is a “game piece” used in board games, such as a bishop used in chess: it just visually represents and embodies a concept to which certain properties (in this case specific permitted moves) are attached.

Tokens are useful because its more practical to use small placeholders rather than the real objects: “human chess” definitely sounds fun but persuading four ordained members of the clergy to move around at your command whilst potentially feasible for a dictator, is a little less practical for the rest of us.

In computing, tokens serve the same purpose: to represent some other object, particularly in a form that is more easily transported across a network. At their simplest, tokens can be used to represent data without containing the data itself, specifically to provide a unique identifier which retains all the pertinent information about the data without compromising its security. An example is data tokens used within the data tokenization, a form of data masking in which sensitive data is replaced with different pseudo-random content that stands in for it – it can be used where sensitive data needs to be safely represented within an insecure environment but where its exact values do not need to be known. An example might be representing customer data in a test environment.

However, tokens are most frequently encountered in a form known as access tokens, in which the token is used to represent either a claimed identity, or the right to perform some specific operation, or both. Access tokens are used in various areas within computing as containers for security credentials. Bearing a token containing security credentials can be used to provide proof of identity. Within the context of computing, a token is not as simple in form as a password. Although a token can be used to provide authentication, it can also specifically contain other attributes, such as stating a given user’s group membership or privileges. This may seem counter-intuitive to allow a user in possession of a token to state what privileges the token grants them (this information would in other systems be stored on the server side), but we shall see shortly how this apparent anomaly is explained.

Tokens can be used to prove identity both by users (in user-system interactions) as well as of systems or processes (in system-system interactions). A simple analogy is to think of tokens as passports or ID badges, which can be presented to prove identity but also contain other data or information. Since tokens are used within access control systems, they must therefore be kept secret and be hard to forge (that is, be tamper-proof).

 

What is a web token?

 

A web token is simply an access or identity token that is used by a web application or web service, within a client-server access model. They have found especially widespread adoption within APIs (Application Programming Interfaces).

 

What is a JSON web token?

 

A JSON Web Token (JWT) is an identity web token that uses JSON encoding to encapsulate a set of claims as textual objects, using JSON’s available data types such as strings, arrays, and key-value pairs. “Claims” are declarations about the user or about the token (that represents the user) itself. When used in an access control system, a claim may assert who issued the token, how long it is valid for, or what permissions the client has been granted.

Some of these claims have specific reserved meanings, but others can be appended as needed. Examples of specific reserved claims are issuer (iss), subject (sub), audience (aud), expiration time (exp), not before (nbf), and issued at (iat).

 

What do JSON web tokens look like?

 

A JSON web token is serialized in base64 URL encoding and transmitted in the form of a string made up of three parts, separated by dots or periods (“.”) in order to provide a byte stream suitable for data transport. An example JSON web token might look like the below when it is in transmission:

Once decoded or deserialized, the original JSON data structure is visible. The first section, the header, contains the type of token being used, and the signing algorithm:

{

"alg": "HS256",

"typ": "JWT"

}

 

The next section in the deserialized file is the “payload” that contains the claims, such as an identity claim and surrounding metadata such as the issuer or timestamp:

{

"sub": "444443",

"name": "John Doe",

"iat": 1515239022

}

 

The last section of the decoded JSON token is the “signature,” a cryptographic checksum that ensures that the token hasn’t been tampered with or altered. The server that creates and issues the JSON web token signs the token and then when it receives the token back in an identity claim it verifies that the header and payload match the signature:

HMACSHA256(

base64UrlEncode(header) + "." +

base64UrlEncode(payload),

your-256-bit-secret

)

The token is signed using a secret that’s only known to the server, so even though the client and the server can both see the user info claims within the token payload, the signed part can only be verified by the server.

 

What are JSON web tokens used for?

 

Because JWTs are signed, they provide a way of ensuring data integrity: that is that the information contained in the payload is guaranteed not to have been tampered with since it was issued. JSON web tokens can therefore be used simply to provide a form of information exchange or data transfer to securely transmit information between two parties.

However, JSON web tokens have found greatest adoption as a mechanism for authorization within an access control system and they are sometimes called bearer tokens when used in this way. Because the structure of JSON web tokens supports an arbitrary number of claims, and is signed against tampering, the basic proof-of-identity that a typical session cookie might provide can also be augmented by other, related claims contained in the token. For example, a JWT may contain role, group membership or access claims that a server can use to determine if a given requested function in a web application, or specific API route, should be accessible to them if requested.

Because of the unique combination of the fact that they are stateless (being self-contained and not requiring server-side storage) and signed, JSON web tokens are particularly well suited to distributed systems or those where the server that issues the token is different to the server on which the resource being accessed is located, known as delegated authorization. This makes them particularly well suited to usages such as federated authentication.

 

How do JSON web tokens work?

 

When used within an authentication context, a user logs in as usual, but instead of being returned a cookie-based session token, for example, they are returned a JSON web token on successful login. Instead of some long, random string that is used as an indexed key to look up a client identity server-side from a database, JWTs claims contain the actual user info itself: no server-side storage is required.

As with any other session token, the JWT is stored on the client side in some form – either transiently within memory or persisted via the localStorage.setItem() method within the DOM’s web storage API, or some equivalent mechanism.

Again, as with a session token, the client then provides the JWT back to the server by attaching it to each subsequent request made. The server can verify the contents of the JWT by evaluating the signature, and then use claims within the token (once it has been validated) to make access control decisions, such as permitting or denying the user to specific routes, services, or resources that they are requesting access to in the HTTP request to which the token is attached. Within API access control, the JWT is typically transmitted within the Authorization header using the Bearer schema. However, the use of JWT as a mechanism to provide sessions for authenticating users has several potential security concerns, as we shall see later on.

When used as an access token, especially within federated authentication systems, it is important that the JSON token contains claims that embodies various constraints, that is restrictions on what actions are permitted. Specific claims within the token can be used to restrict the scope that the token is valid for (such as whether to allow read-only or full read-write access) or to bind the access token to a specific sender.

 

Are JSON web tokens similar to HTTP session cookies?

 

As we have seen above, JWTs can be used to replace typical session cookies but their contents are a lot richer and contain meaning rather than being an indexed key (ID) only. Critically, JWTs are stateless in that there is no server-side storage and no maintained server-side state. This has some potential security issues as we shall see shortly.

 

What benefits do JSON web tokens provide?

 

The primary reason for JWT’s popularity lies in the fact that it is an open standard, with support across a range of platforms, operating systems, languages, and frameworks, and also because it is simple to implement from a developer perspective. In contrast to a session-based authentication mechanism that may require interaction with a database tier, potentially requiring server deployment and dependence on a database team, JWT can be implemented entirely in code: something that is highly appealing in the context of cloud web services.

The lack of reliance on a server-side lookup of client permissions (since they are contained in the token itself) means that JWT-based access control scales significantly better, and is more resilient, than session-cookie based authentication systems that are reliant on a database backend to store user attributes. The time taken to evaluate an access request from a user is only as long as it takes to perform a simple hash verification within the web tier, rather than perform at least one round-trip request to a backend database system.

 

What security issues are there with JSON Web Tokens?

 

Although there are compelling reasons to use JSON web tokens, there are also several potential security weaknesses to be aware of, especially if not familiar with how JWTs are intended to operate within authentication systems and if assumptions from other identity proof mechanisms are applied.

 

Sensitive Data Storage

 

JWTs are sent to the client and returned to the server with every subsequent request. Even though the contents are encoded and signed, they are not encrypted by default. This can catch some developers out, particularly if they are new to JWT usage or unclear on cryptographic principles and mistakenly believe that cryptographic signing provides guarantees of confidentiality – this is an especially prevalent mistake since the contents certainly look encrypted once encoded. Sine the payload is sent in plaintext, and specifically provides a mechanism for rich content via claims, it is easy to see how sensitive information is sometimes included within issues tokens on the assumption that it is secure. If you need to include sensitive information within a JSON web token, then encrypted JWTs can be used, but generally it is best avoided altogether.

 

Authentication/Authorization Confusion

 

JSON web tokens are relatively flexible in their potential implementations because the standard is so flexible. Specifically, they can be used as both ID token (that validate an identity) or as access tokens (which validate identity and also verify access claims). The difference is somewhat subtle, but ID tokens ensure only that a user is authenticated – that is, that they are who they claim to be. They do not provide authorisation – that is, whether or not that authenticated identity grants them the right to access a given resource.

If a token issues for identification/authentication purposes (an ID token) is used by a server or API to make an access control decision that requires an access token then it may be possible for clients to simply access all resources, regardless of whether or not they should be able to. This kind of access control failure is in the same general class of error as seen in weaknesses such as “Insecure Direct Object Reference” (IDOR) or “Broken Object-Level Authorization” (BOLA) – a logical confusion as to what claim has been substantiated by the identity proof.

 

Lack of Session Expiry

 

Once it has been signed and issued, a JSON web token is valid forever if no expiration date was given, since the cryptographic signature remains valid. There is no server-side state that is maintained or mechanism that could be used to revoke them. Within classical session token usage, a server maintains a session state table – typically in a database – in which attributes such as the session token issue and expiry time are recorded. This same mechanism is not available in JWTs when used as access tokens.

This has implications such as being unable to log out a user or force a token to expire. A user could log out of a system but since the JWT is self-contained, it will continue to work if provided to the server until it expires. If an attacker is able to get access to the token (or if another user uses the device, such as on a shared computer, they could continue to use the JWT to authenticate until it expires. It is therefore generally recommended to always set an expiry time on issued tokens, as well as to make this expiry time relatively short – say 5 minutes – in order to minimise this attack window.

Specific reserved claims exist for setting the expiry times of JWTs, including the “exp” claim, containing the expiration time, the “nbf“ or “not-before” time claim, and the “iat” or “issued at” claim. All three claims can be set and evaluated in order to reject tokens which are too old to be accepted as valid.

 

Failure to check audience or scope

 

It is obviously important that an API or other resource only allows authorised users to access it. Within the context of JSON web tokens, this means that resources should only accept token that are meant for it, not simply all valid tokens.

This may seem obvious, but it is possible for a server implementing JWTs to either issue a token without constraints such as scope or audience, or else fail to verify these constraints when validating tokens that accompany access requests. In the worst cases, an ID token stolen from another application entirely could even be used to access a victim API if all it does is verify the token validity and doesn’t check the claims within it relating to audience or scope.

 

Signature Verification and the “None” algorithm

 

Within computer security, it is a general principle that security decisions should be made server-side rather than client-side and client-side enforcement of server-side security is considered to be a form of security weakness and protection mechanism failure. The fact that JSON web tokens entrust access attributes to a client-side token does not directly undermine this, since the claims contained in the token are signed by the server and are expected to be validated by it. However, it does mean that JSON web tokens are an atypical pattern and can cause confusion that can lead to exploit of this principle.

There are a range of ways in which the weakness of allowing client-side data manipulation can be introduced despite the use of data signing within the tokens.

An early design flaw in the JWT standard uncovered in 2015 meant that there were several critical vulnerabilities in popular JWT libraries that could be exploited in order to manipulate the data client-side. Fundamentally, there was a “chicken and egg” situation in which the server needed to determine what algorithm was used to generate a JWT’s signature: it could do this by looking at the “alg” field in the JWT header… except that the server hasn’t validated the token yet, which means that it hasn’t validated the header. In order to validate the token, the server would have to allow attackers to select which method should be used to verify the signature.

Many JWT libraries supported the “none” signature algorithm, a special case in which the “alg” claim could be used to inform clients that the JWS is actually not signed. Accepting this algorithm on the server-side meant that a malicious client could manipulate the token contents, set the algorithm type to “none,” and the server would validate all claims made within the tokens. Since a malicious client could craft a JWT containing whatever payload they want, they could gain arbitrary account access on any target systems that supported the “none” algorithm method.

Although all common JWT libraries have long been patched against this weakness, anyone implementing JWTs directly using their own implementation can still fall victim to this weakness unless the “none” algorithm is explicitly rejected or disabled.

 

Weak Signature Algorithms

 

The symmetric key algorithms used to sign JSON web tokens can be vulnerable to simple brute force attacks if the key isn’t strong enough. Various cryptographic algorithms are available within the JWT standard for signing, including HS256, RS256 and ES256. HS256 in particular is only as strong as the secret key that is used in generating it. When a small key is used, the resulting signature can be brute-forced relatively trivially

The RFC standard for the algorithm recommends that the secret key used must be at least as large as the hash output that is generated in order to provide robust security against brute force attacks – for the HS256 hashing algorithm that would mean ensuring that the key was at least 256-bits (32-bytes), for example:

9aZFBhlxt1UxqFwidiCfJWQ4aCCLEbMu

 

Algorithm Confusion

 

In more secure implementations that use an asymmetric signing algorithm, such as RSA, it may still be possible to trick the server-side code into accepting a weaker algorithm. As outlined in the previous section, the HMAC signing algorithm has its flaws as it relies on the use of a symmetric key to ensure the integrity of the data transmitted within the token. Other algorithms, such as RS256 use an “asymmetric” key pair to sign the token (stored server-side). This consists of a private key, which the server uses to sign the token, and a mathematically related public key that can be used to verify the signature. In token verification solutions that uses asymmetric keys, the public key is typically provided within the JWT itself or referenced to an external location such as a JSON Web Key Set (JWKS) endpoint, disclosing the public key over HTTP.

Whilst server-side code may be setup to verify token signatures using a private key, problems can arise when the underlying library uses a single, algorithm-agnostic method for verifying signatures. Meaning, that the server will verify tokens using both asymmetric and symmetric algorithms. If a malicious client provides a token with a “alg” claim of a symmetric algorithm like HS256, the server will use a generic “verify()” method that treats the public key as an HMAC secret. This means that an attacker could sign the token with HS256 using the public key, and the server will use the same public key to verify the signature.

 

Client-Side Storage

 

Storing tokens on the client side is possible via the DOM’s web storage API using “localStorage” or “sessionStorage” as well as a number of other methods , depending on the client-side technology in use. Any tokens that are accessible to and retrievable by client-side code become vulnerable to client-side exploits. In the case of a web application this means that if any of the JavaScript scripts on the web server are compromised – including many third-party scripts that may be loaded, then it is highly likely an attacker may be able to access a user’s stored JSON web tokens within the browser.

There is no absolutely secure way of storing JWT tokens on the client, but in general an HTTP cookie with the “HTTPOnly” flag set is one of the safer mechanisms, since it is not accessible via client-side scripts in most cases. There are exceptions, however, including the possibility of Cross-Site Tracing (XST) attacks. These combine XSS with other techniques to access cookies even if the “HTTPOnly” flag is set. The use of a secure cookie implementation to transmit a JWT limits it’s use to the domain in which the cookie was transmitted, potentially breaking any OAuth or OIDC authentication mechanisms in place. In such a scenario, considerations should be given to storing any client tokens in memory combined with a secure “refresh_token” implementation.

 

Man-in-the-Middle (MITM) Attacks

 

Since JWTs are used in access control, it is important that their contents are secure from being read. Mechanisms exist within the JWT standard to natively encrypt the token at rest, using a form known as JWE. However, it is also best to ensure that a JSON web token is secured at the transport layer too, by ensuring that it is always transmitted across a secure connection (HTTPS/TLS). Most websites and APIs these days will be using HTTPS as default, but if not, then actions requiring JWTs should use secure HTTP connections at least. If HTTP cookies are being used for the JWT storage and transmission, then the “Secure” flag can be set on the cookies when issued to ensure that the client only ever returns them over a secure connection and never in plaintext.

 

Server-Side Injection Attacks

 

We saw above how client-side injection attacks could compromise JWT security. However, server-side injection attacks are also possible, since the JWT is parsed by the server and its values can be used as input in certain server-side operations. It is therefore recommended to treat the contents of JWTs as untrusted user-provided input, and to validate them before they are used, especially if used in any form of backend operation, query, or command. Ensuring that you sanitize any value retrieved from a JWT can help to ensure that an application is protected from common forms of attack such as SQL injection attacks.

Furthermore, explicit trust in passing a JWT to an underly library without thorough validation should be warned against. In 2017 Open Web Application Security Project (OWASP) included “Insecure Deserialization” in their top ten issues for the year following an increase in the number of related public vulnerabilities appearing that year. Insecure deserialization issues were discovered that affected both JSON and XML libraries across a variety of platforms, which could be exploited to carry out code execution and, in some cases, gain remote access, all due to improper validation and sanitization of serialized user input. In turn several JWT libraries were also affected as they had relied upon the same libraries. Therefore, it is recommended to ensure that all server-side libraries are continually kept up-to-date and patched inline with a reliable and robust secure patching policy.

 

Summary

 

Many of the weaknesses in JWTs relate specifically to their use within authentication and access control mechanisms as session tokens. Since the length of a session is not known ahead of time, JWTs used in this way must have a relatively long-lived validity, meaning that they are vulnerable via a longer attack window to brute-force attacks, reply or MITM attacks and other weaknesses. Although some forms of vulnerability are common to all JWT usage (such as server-side injection attacks and use of the “none” algorithm), many of the other weaknesses can be avoided entirely or at least made far less vulnerable if the tokens are used only in applications where they can have more aggressive expiry times applied to them.

If restricted to uses where they are valid as single-use authorization token which are then discarded, JWTs can be issued with much shorter validity periods, and many vulnerabilities above made impractical to exploit. In this implementation, JWTs are intentionally short-lived and issued specifically to authorise a specific action on a one-off basis, rather than granting a set of capabilities (claims) that can be evaluated repeatedly over time to assess a series of chained access requests.

 

How AppCheck can help

 

AppCheck help you with providing assurance in your entire organisation’s security footprint. AppCheck performs comprehensive checks for a massive range of web application vulnerabilities including missing patches, weak and outdated ciphers, and weak authentication.

The AppCheck Vulnerability Analysis Engine provides detailed rationale behind each finding including a custom narrative to explain the detection methodology, verbose technical detail, and proof of concept evidence through safe exploitation.

 

About AppCheck

 

AppCheck is a software security vendor based in the UK, offering a leading security scanning platform that automates the discovery of security flaws within organisations websites, applications, network, and cloud infrastructure. AppCheck are authorized by the Common Vulnerabilities and Exposures (CVE) Program as a CVE Numbering Authority (CNA).

 

Additional Information

 

As always, if you require any more information on this topic or want to see what unexpected vulnerabilities AppCheck can pick up in your website and applications then please contact with us: info@appcheck-ng.com

 

Get started with Appcheck

No software to download or install.

Contact us or call us 0113 887 8380

Start your free trial

Your details
IP Addresses
URLs

Get in touch

Please enable JavaScript in your browser to complete this form.
Name