My question assumes the implementation of the JWT is sound, and it's more about what you do afterwards with the valid payload.
I am issuing JWT tokens, and then each token is verified to confirm the identity of the user. But is it necessary to still validate the fields once the token has been validated?
For example, here's a sample token payload:
{
“iss”: “example.com”,
“exp”: 1426420800,
“company”: “example”,
“userid”: 123456789,
"name": "Bob"
}
Do I need to validate that 'userid' is an integer? And validate 'name' is a string of a certain length?
Do I need to validate that userid is an integer? And validate name is a string of a certain length?
Assuming that your JWT implementation is sound as you mentioned in the question and assuming that you trust the server that issued the token, such level of validation is not necessary after checking the signature.
Before accepting the token you must ensure that the token is valid. Here are some validations you must consider:
Validate the signature to ensure that the token was not tampered with.
Ensure that the token is not expired by checking the exp claim.
If you use the nbf claim, ensure that it's not too early to accept the token.
Validate other claims such as iss if you need to.
Most of sound JWT implementations support those validations.
As mentioned in Lutz Horn's answer, you should rely on JWT for authentication (who the caller is) only. For authorization (what the caller can do), look up the caller roles/permissions from your persistent storage to get the most updated information.
This depends on your server. If it will do anything using the JWT claims, for example store some data, it should validate that the executing user exists and is authorized to do this.
The JWT only handles authentication: Prove that the user is who he is and that he presented the necessary information (password) to prove this. JWT does not handle authorization: check what the authenticated user is allowed to do.
Related
I just realized that the userinfoendpoint doesn't give any useful info about the logged in user.
Now, I saw that you can get an id_token from ADFS tokenendpoint. This id_token is actually a JWT which contains the unique_name.
Now my question is, if it is safe to use this info without signature validation (since we don't have the private key of the HS256 algorithm and validation is as far as I understood, a thing for the issuer not for the client).
• There are two scenarios to your question of whether it is safe to use this info from an ID_token. First, your client, i.e., the application or authorization server will validate the token just like it validates the access token for any tampering. Also, it can validate the issuer to ensure that the correct issuer has sent back the token. Since there are many libraries to validate an ID token, you should use them for ID token validation purposes.
• Also, only confidential client applications should validate an ID token as their token holds a secret while public applications don’t benefit from validating an ID token as there is always a risk of a malicious user who can intercept and edit the keys used for validation of the token.
• As you are speaking of the case when you don’t have the private key to the algorithm used for encrypting the ID token, it must be a confidential client application. Thus, validating the ID token on the lines of access token and confirming the below claims are validated by your token validation library, you can then use the information retrieved from these claims for your purpose. The claims that need to be validated are as follows: -
Timestamps: the iat, nbf, and exp timestamps should all fall before or after the current time, as appropriate.
Audience: the aud claim should match the app ID for your application.
Nonce: the nonce claim in the payload must match the nonce parameter passed into the /authorize endpoint during the initial request.
Please find the below documentation link for more in-depth details on validating the tokens and the inherent process involved in it: -
https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens#validating-tokens
No, sadly the userinfo endpoint only gives you a "sub".
You can validate the JWT yourself.
You should always check the signature.
I have a general question regarding JSON Web Token (JWT).
If the JWT is stolen from the client (say, it was stored as a cookie or the app's database) by hacking or physical access, it can be used to send to the server which the server will think it is the legitimate user. Is this correct?
Is there any common or standard practice to guard against this, for example, by sending the type of device/browser or some reference code together from the client and the server checks it matches additional data the JWT token was generated and stored with. (However, I read that the standard practice is not to store anything on the server.)
Please advise as I need to implement Java JWT (JJWT), RESTful Java Jersey and Google Web Toolkit. (I've been reading documentation such as this: [https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage]).
Thank you!
Possesion of a JWT is the proof of authentication. An attacker who stoles a token can impersonate the user.
So, keep tokens secure:
use a TLS channel
add extra security measures depending on the type of storage. Cookies are vulnerable to CSRF attacks. use HttpOnly if you do not need to access token from javascript. LocalStorage is vulnerable to XSS attacks
set short expiration time on authentication tokens and require credentials if token is expired
Blacklisting is not useful because you won`t know that a JWT has been stolen. And its usage breaks stateleness, one of the advantages of JWT
Additionally is possible to add the IP the token, but consider the usage scenario because it can be problematic on mobile devices or systems behind a proxy
On the client you are building the JWT like:
byte[] key = getSignatureKey();
String jwt = Jwts.builder().setIssuer("myTestApplication")
.setSubject("myTest")
.setExpiration(expirationDate)
.put("scope", "testing")
.signWith(SignatureAlgorithm.HS256, key)
.compact();
On the server side you can verify the JWT in regards to the the key and the expiration date exp (and more i.e. creation date, issuer iss, audience aud):
String subject = "notMyToken";
try {
Jws jwtClaims = Jwts.parser().setSigningKey(key).parseClaimsJws(jwt);
subject = claims.getBody().getSubject();
//OK, we can trust this JWT
} catch (SignatureException e) {
//don't trust the JWT!
}
Stealing the JWT should be avoided by using SSL,...but if the JWT is stolen there would be the risk of replaying exactly this JWT - right. That's where jti comes in.
The jti (JWT ID) claim provides a unique identifier for the JWT. The
identifier value MUST be assigned in a manner that ensures that there
is a negligible probability that the same value will be accidentally
assigned to a different data object; if the application uses multiple
issuers, collisions MUST be prevented among values produced by
different issuers as well. The jti claim can be used to prevent the
JWT from being replayed. The jti value is a case-sensitive string. Use
of this claim is OPTIONAL.
With this identifier you could recognize if this ID was already sent (you have to blacklist it on the server side which somehow undermines the nature of JWT). Because you should use the expiration date you could clean the IDs if the expiration date leads to a SignatureException.
However, if the 'hacker' stole the JWT out of the database, as you wrote in the question, you have further problems beside the stolen JWT probably, because than the attacker could also steal other data etc.
Hope this helped a bit.
So there's already an example for authenticating by mutating "login" and returning the auth token as part of the response - does anyone have any ideas how I might use a secure cookie instead? I'd really strongly prefer to use this if I can, as it's an extra barrier against sessions being hijacked by an XSS attack on my relay app. I'm using Akka HTTP.
Ideas I've had so far:
Set the token value on the context as a mutable value during query execution, then grab it out inside a map call (bad)
Set the token on the response as in the example, then in a map call modify the response to remove the auth token and set it as a cookie instead (less bad, but not exactly great).
Is there something better than I haven't thought of?
A 'secure cookie" I assume you are referring to a signed cookie?
Signatures do not hide cookie contents, the contents are simply treated as being tampered if the signature failed to validate, but the cookie is public/readable anyway
If the cookie itself being present is how a session will re-auth for each subsequent request (maintain session, aka; 'session riding' in attacker speak) then it being signed or not is functionally no different than losing an 'auth token' (assume you mean an OAuth2/OIDC/JWT but not an API Key?) via XSS
So far we have discussed 'auth' in the sense of authorisation (authz), that having a token authorises you to make the request, the response trusts you are who you claim - i.e. the system of using a cookie or a token that implies this is merely a trust-based system, no real authorisation 'mechanism', only unverified trust in the cookie or token
To apply an authorisation 'mechanism' for signed cookie, or token, there must be a mechanism the server can use to verify the sender is the authentic (auth in the sense of authentication aka authn). Does your application code apply one-time authn and 'bearer' token/cookie trust without authz? Bearer authz means you have th 'thing' and if you have it you are authorised. Because Bearer authz is a blind, unverified, method of authz that if the 'thing they bear to you is stolen anyone can be a bearer and gain authz.
Or do you want to apply an authz mechanism?
If you are doing bearer only, the signed cookie or auth token is equivalent security, from the attackers perspective.
If you are interested in applying authz mechanisms so the token can be verified for authenticity, this mostly requires the requester to have a secret to 'sign' the token or cookie with, a secret they have that signing can prove they have it without sending it over the wire to the server with the request (and expose the secret).
To learn more about this start with OWASP Authz page (I contributed to) here https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
If this is no longer relevant, please accept the answer for other readers who come across it.
I receive two JWTs: an OpenID Connect ID token (id_token) and an Access Token (access_token). The situation with OpenID is more or less clear - I can validate it using a JWKS Endpoint: https://smth.com/JWKS.
as in example (https://bitbucket.org/b_c/jose4j/wiki/JWT%20Examples):
HttpsJwks httpsJkws = new HttpsJwks("https://smth.com/JWKS");
HttpsJwksVerificationKeyResolver httpsJwksKeyResolver = new HttpsJwksVerificationKeyResolver(httpsJkws);
jwtConsumer = new JwtConsumerBuilder()
.setVerificationKeyResolver(httpsJwksKeyResolver)
.setExpectedAudience(...)
.setExpectedIssuer(...)
.build();
The question is how to proceed with the Access Token. I can extract from it the userId and userDetails, but I guess I need also to validate it?
If I try to validate the Access Token the same as for the ID Token, I am getting this error:
UnresolvableKeyException: Unable to find a suitable verification key for JWS w/ header {"alg" : "RS256", "kid":"1"}
And indeed there is no key for "kid" : "1", Also this value "1" seems kind of strange?
Am I doing something totally wrong?
It sounds like you are implementing the role of OpenID Connect client or Relying Party. The two tokens, ID token and access token, serve different purposes and should be handled differently by the client. The ID token is intended for the client and enables authentication of the end-user at the client. The client must validate the ID token (verify the signature and validate claims like exp and aud, etc.) before allowing the end-user in. The access token, however, is for the client to use to access resources or APIs but is not directly intended for the client to consume or validate. The access token is opaque to the client and the client shouldn't care or know about its details. In fact, access tokens aren't always JWTs. In OpenID Connect, the access token is used to call the user info endpoint (with the HTTP header, Authorization: Bearer [access token]) to get more claims/info about the end-user.
The value of "1" for the kid is totally legal but it is referring to a key that the AS/OP and the user info endpoint know about somehow. It is not a key at the OpenID Connect JWKS endpoint. "1" isn't a key that the client needs to know about because the client isn't supposed to directly verify the access token.
I need to implement an authentication scheme for a RESTful architecture. From several articles which I have read include basic Authentication using HTTPs and Session management using Cookie.
However I'm not well understanding the use of cookie. What i understands is that user first sends credentials. The server checks if the credentials are Ok. If yes, the server generates an authorization token and place it in the cookie. Onwards, on each and every request, server checks the validity of the token in the cookie.
But how does the server know that the content of the cookie is valid. Does it stores it somewhere and then it compares it??
The key point here is the authorization token. When generating one and sending back to the client, you store the auth token along with the username in let's say a database. You store the auth token in the cookie. The client on subsequent requests sends you the username and the cookie alongwith which contains the auth token. You verify this token against the supplied username and then perform the action per need.
However, do note that settings cookies makes your webservice call stateful and defeats the purpose of REST.
To achieve authentication/authorization, instead of setting the authorization token in the cookie, send it back as a response value. The client reads the value of auth token and then supplies the same in every REST request as a parameter of request body. Thus, you won't need to set cookies. This you may term as the toned down and simpler version of what is implemented in OAuth based API access.
I'm not an expert, but a good starting point to understand this is the section on Sessions in Hartl's book.
If I'm not mistaken it works as follows:
When the token is created, it uses a formula, e.g. the username and a unique user key (a salt) encrypted together. Both the username and the salt are stored in the database, and the salt is unique to that user. So, as you would do to compare if passwords match, to check the validity of the cookie you recreate the token and compare it to the one in the cookie. If it matches, then the right user is logged in and therefore authorised.
Hope this helps, or at least points you in the right direction :)