You had questions, and we’ve got answers!
On slide 26 is the HS256 or RSA key used by the attacker to sign the token?
This attack happens when you are using an asymmetric algorithm (RSA) and the attacker replaces it with a symmetric one (HMAC like HS256 in our example.)
In regular use (expected by the API implementation):
- Only the token issuer has the RSA private key and can sign the token
- Private RSA key required to validate the token is public, known to anyone who needs to validate the signature
- Attacker does not have the private RSA key and thus is not able to forge token signatures
To perform the attack, attacker:
- Makes the token changes they want for their attack
- Change the algorithm (alg) field in the token header from asymmetric to a symmetric algorithm
- Sign the token using HMAC (symmetric) algorithm with the key that is the RSA (asymmetric) public key. The public key is often known because in the RSA context it is only used to verify signatures and never to create ones.
- The victim receives the API call with the forged token.
- If the victim just blindly verifies the token signature with the algorithm in the token header (which the attacker changed from RSA to HMAC!) and the same key that they have been using (the RSA public key) – that verification will succeed because HMAC is symmetric and thus the same key is supposed to be used both to sign data and to validate the signature.
Given its insecurity, why does the specification allow for no algorithm? In what use case would that be applicable? Just testing or is there a real-world use case for no alg?
“None” has been added to the JWT specification mainly for testing purposes and for situations in which there has been an explicit decision by the system’s architects to not sign the tokens altogether.
Quoting JWT security best practices document:
“That said, if a JWT is cryptographically protected end-to-end by a transport layer, such as TLS using cryptographically current algorithms, there may be no need to apply another layer of cryptographic protections to the JWT. In such cases, the use of the “none” algorithm can be perfectly acceptable. The “none” algorithm should only be used when the JWT is cryptographically protected by other means. JWTs using “none” are often used in application contexts in which the content is optionally signed; then, the URL-safe claims representation and processing can be the same in both the signed and unsigned cases.”
We, at 42Crunch, believe in zero trust approach toward any data coming from API clients. Tokens are especially sensitive because they serve as a foundation for authentication and authorization decisions. Thus, we believe that real-life scenarios should exclude “None”, pick a proper algorithm and enforce its use. Most industry vendors follow a similar approach.
You can read more here: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
What’s the benefit for the attacker to change the algorithm? Wouldn’t changing the content break the signature anyway?
The idea behind changing the algorithm is to enable attacker to forge the token signature:
- Using “None” algorithm allows to remove the signature requirement altogether
- Changing asymmetric algorithms to symmetric allows the attacker to use the known public key that the API implementation is using to verify the signature (that the attacker now creates!) and thus make the forged token valid.
Of all the grant types, is the “Auth code grant” more relevant to API security and user metadata? What about implicit, client credentials and other types? Are they not suitable?
We should probably do another webinar specifically on OAuth2 security best practices. The exact grant type to be used depends on the scenario, however, Implicit grant and Resource Owner Password Credentials grant are no longer considered secure and should not be used.
Other notable OAuth2 current security best practices are:
- PKCE is required for all OAuth clients using the authorization code flow
- Redirect URIs must be compared using exact string matching
- Bearer token usage omits the use of bearer tokens in the query string of URIs
- Refresh tokens for public clients must either be sender-constrained or one-time use
See current OAuth2.1 draft for details on the current OAuth security recommendations: https://tools.ietf.org/html/draft-ietf-oauth-v2-1-00
Can you have specific validations per API so you know specifically what aud is allowed per API?
Yes, 42Crunch allows to define audience and other JWT requirements on a per API level.
What is the deployment model for the 42Crunch firewall which protects against these JWT attacks? Does it deploy like a gateway or closer to the application?
42Crunch firewall can be deployed both in a central gateway-style mode and as a sidecar proxy within the same pod as the microservice implementing the API.
At the last bit, these terms were used “exchange OPAQUE TOKENS with a REAL JWT TOKEN” “don’t send FULL TOKENS” —- can you expand again what the differences with those tokens.
Opaque token is an identifier that can be used to retrieve full information about the caller. The API implementation then does not decode the token but rather is using it to retrieve information from some sort of an internal database or service.
You can learn more about this architecture pattern here: https://curity.io/resources/architect/api-security/phantom-token-pattern/
Real JWT / full tokens are the JWT tokens we covered in the webinar. This is an encoded JSON structure with the actual information about the caller. Anyone decoding that token can get information contained in the token. Thus, unencrypted JWT tokens containing sensitive information should not be used in situations when the token is available to client applications and thus potentially in the attacker’s hands.