Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parse jwt without key support #135

Closed
notedit opened this issue Jun 18, 2016 · 11 comments
Closed

parse jwt without key support #135

notedit opened this issue Jun 18, 2016 · 11 comments

Comments

@notedit
Copy link

notedit commented Jun 18, 2016

the python jwt support that decode the payload but not verify.

jjwt support that?

@LGRI
Copy link

LGRI commented Jun 19, 2016

This is a essential component for jwt.
jjwt seems to cover only server side jwt handling, but not client side.
I don't wish to expose my verify key at Android app, only decode the payload if required to.

@lhazlewood
Copy link
Contributor

This is incorrect - JJWT is meant to be used for both server and client-side scenarios.

What you are asking for is to ignore the signature on a valid JWS and read the JWT header and body anyway. This violates the JWS specification, and because of that JJWT won't do it for you automatically (JJWT is a spec-compliant library).

That said, if you still want to violate the specification and read the header and body for client-side scenarios, it is trivial: just 'chop off' the last token in the JWS string (but not any period characters).

For example, consider this JWS:

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

You can 'chop off' the last 'part' after the last period character ('.'), which is the JWS signature. If you do that, you are left with:

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.

And then read that JWT in your client side code as a 'normal' JWT (non-JWS).

@LGRI
Copy link

LGRI commented Jun 28, 2016

@lhazlewood So for spec-compliant reason, we all should expose our secret key to our client, right? Then it violate the rules of web security, for spec-compliant reason. The first & second part of the JWT can be decoded by anyone reason is fairly simple: for decoding by anyone at client-side, without exposing the secret key. If the JWT is designed to be encrypted, why bother to include the first and second part? The JWS part is enough for all information.

@lhazlewood
Copy link
Contributor

lhazlewood commented Jun 28, 2016

@LGRI Of course you shouldn't expose keys in the client - and no one said or even implied that. How did you infer that?

I could be wrong, but it seems as if many people may not understand the differences between a JWT, a JWS and a JWE. Anyone who uses any JWT library (JJWT or not) needs to know what these things are. Libraries like JJWT only facilitate working with these concepts, so people need to understand the concepts first.

If the JWT is designed to be encrypted

We were talking about a JWS (a signed JWT). A JWS is not encrypted. It is signed. These are fundamentally different cryptographic concepts.

The JWS part is enough for all information.

I don't know what this statement means. The 'JWS part', I can only assume, means the signature token - the part after the 2nd period character. This certainly isn't enough for all information.

Let me try to make things crystal clear here:

Consider a JWS created by the server that looks like this:

foo.bar.baz

Send that to the client. It's fine - the client can't manipulate it and send it back to the server without the server knowing about it (and rejecting it).

The client code can chop off the baz suffix so now the client has:

foo.bar.

(notice the trailing period). This is a 'normal' (unsigned) JWT. Not a JWS or a JWE.

The client can take this JWT (it is no longer a JWS) and use JJWT or any other library to parse the JWT. Because there is no signature, no key is required when parsing this new JWT.

@LGRI
Copy link

LGRI commented Jun 29, 2016

@lhazlewood The JWT signature is signed by the secret key with payload and header, which means it encrypt the payload and header with secret key. If the client needs to validate it all the time when they received, it better be a JWE. The validation is only needed when it received by server, not client, that's why jwt's header and claims are only encoded with base64, and sensitive data in claims are not advised. I refered the "JWT signature" as JWS, if there's anything wrong everyone is welcome to correct me anytime. The way I inferred that I should expose my secret key is by using your library, for compliant to spec of validating JWT procedure. I know the anatomy of JWT, I can decode the claim and header by myself, the key point of my issue is checking the expiration of JWT without validating them with your library. How can I achieve that? Any advice for doing it on my own?

@lhazlewood
Copy link
Contributor

lhazlewood commented Jun 29, 2016

if there's anything wrong everyone is welcome to correct me anytime

I don't mean any disrespect, but I feel it is important to correct some of your statements that are incorrect so that other people reading this thread understand correct terminology. Everyone who uses JWT/JWS/JWE needs to understand these concepts before using any JWT library.

The JWT signature is signed by the secret key with payload and header

This is incorrect. It should be:

"A JWS is created by signing a JWT header and payload with a signing key and the resulting compact string is called a JWS"

which means it encrypt the payload and header with secret key.

This is definitely not correct. _JWS does not use encryption_. There is no encrypting of the payload. Cryptographic signatures are not encryption. People using JWT/JWS/JWE should understand fully the differences between cryptographic signatures and encryption/decryption - they are fundamentally different things.

that's why jwt's header and claims are only encoded with base64, and sensitive data in claims are not advised.

This is not correct. All parts of a compact JWS are base64Url encoded (not base64), including the signature. You just can't base64url-decode the signature and read it, because it won't make any sense to a human.

the key point of my issue is checking the expiration of JWT without validating them with your library. How can I achieve that? Any advice for doing it on my own?

I don't know why you're asking this question - I already gave you the answer above. I'll re-paste the answer here:

Let me try to make things crystal clear here:

Consider a JWS created by the server that looks like this:

foo.bar.baz

Send that to the client. It's fine - the client can't manipulate it and send it back to the server without the server knowing about it (and rejecting it).

The client code can chop off the baz suffix so now the client has:

foo.bar.

(notice the trailing period). This is a 'normal' (unsigned) JWT. Not a JWS or a JWE.

The client can take this JWT (it is no longer a JWS) and use JJWT or any other library to parse the JWT. Because there is no signature, no key is required when parsing this new JWT.

@lhazlewood
Copy link
Contributor

Here is the Java code for the above answer - you can put this logic in your client:

int i = jws.lastIndexOf('.')
String withoutSignature = jws.substring(0, i+1);
Jwt<Header,Claims> untrusted = Jwts.parser().parseClaimsJwt(withoutSignature);

The important point here is that you (not JJWT) are violating the specification by manipulating the JWS, and you're doing it in a calculated way based on your specific use case. This is fine for individual use cases, but probably not for a spec-compliant library like JJWT.

@oguzhangedik
Copy link

lhazlewood Thanks for your answer.

@pcsantana
Copy link

Hi!
@lhazlewood I tried to use your example in an Android app:

int i = jws.lastIndexOf('.')
String withoutSignature = jws.substring(0, i+1);
Jwt<Header,Claims> untrusted = Jwts.parser().parseClaimsJwt(withoutSignature);

But I'm getting the exception io.jsonwebtoken.UnsupportedJwtException: Signed JWSs are not supported.
The library changed since your comment or maybe I'm doing something wrong?
Thank you!

@jwtk jwtk deleted a comment from pcsantana Jul 5, 2018
@jwtk jwtk deleted a comment from oguzhangedik Jul 5, 2018
@jwtk jwtk deleted a comment from oguzhangedik Jul 5, 2018
@Jazzbear
Copy link

Jazzbear commented Dec 8, 2018

Hi!
@lhazlewood I tried to use your example in an Android app:

int i = jws.lastIndexOf('.')
String withoutSignature = jws.substring(0, i+1);
Jwt<Header,Claims> untrusted = Jwts.parser().parseClaimsJwt(withoutSignature);

But I'm getting the exception io.jsonwebtoken.UnsupportedJwtException: Signed JWSs are not supported.
The library changed since your comment or maybe I'm doing something wrong?
Thank you!

I tried this in my android app, with minimum api version of 16 and it worked just fine.
I found that i had another issue though with using a newer unrecogniced version of the HmacSha256.

My app was consuming my own backend asp.net core 2.1 api. And the JWT's it distributed was signed with HmacSha256Signature insteadof just HmacSha256. The reason for this was i had read that the HmacSha256Signature was newer and had deprecated the other one. However the JJWT libary that i used did not support this new signature, so i changed my generator and then used the above method @lhazlewood to split the payload from the signature and then i could read the claims.

@lhazlewood
Copy link
Contributor

@Jazzbear

'HMAC using SHA-256' is required by JWT RFC 7518 Section 3.2. In that section, it identifies https://tools.ietf.org/html/rfc2104 as the algorithm implementation for 'HMAC using SHA-256'. In the JDK, this algorithm is identified by the name HmacSHA256.

If ASP .NET's HmacSha256Signature algorithm does not produce something that is verifiable by the JDK's HmacSHA256, then ASP .NET's HmacSha256Signature algorithm is not suitable for use with JWTs because it is not JWT RFC specification-compliant. That's why JJWT doesn't support it. HTH.

@jwtk jwtk locked as resolved and limited conversation to collaborators Dec 10, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants