9

I am working on a server-client web application, and as an authentication scheme, I am issuing base64 encoded json web tokens. Consider the following token...

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

Decoded as such...

{
  "alg": "HS256",        // header
  "typ": "JWT"
},
{
  "sub": "1234567890",   // payload
  "name": "John Doe",
  "admin": true
},
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), 'secret') // signature 

My concern is with the payload portion of this token, where I wish to supply defined claims e.g. "role": "readonly". My concern is with these values being visible and tampered with by the end user once issued. Modifying this portion will not invalidate the signature check. I don't wish to persist any data on the server to re-check/compare issued tokens - I wish to keep the server completely stateless.

I thought maybe signing the token, encrypting it via AES 256, and using this as my "token". The flow would be summarized as such...

  1. generate and sign base64 encoded token
  2. encrypt token server side via AES 256
  3. Issue encrypted token to client


  4. request recieved, encrypted token supplied

  5. decrypt token server side
  6. validate base64 encoded original token signature (now able to ensure claims have not been altered)

My thoughts are, the claims (payload) will not be seen, and any tampering with this encrypted value will obviously not decrypt as expected server side. My question is - is this viable? I couldn't find much on the web for encrypting whole tokens. Is there a better way?

  • 2
    Why wouldn't claims like role be included in the signature? I believe that the entire contents of the JWT is signed. – Neil Smithline May 20 '16 at 21:51
  • @NeilSmithline thanks for the comment on this. I would expect that as well, but if I validate an originally signed token by modifying the contents, I still get a valid check. Perhaps node-jsonwebtoken is not working as I expect, or I'm missing something alltogether. I hope you're right, honestly, and I'm just missing something – scniro May 20 '16 at 22:00
  • The abstract of the spec states that claims are digitally signed or integrity protected. I'm not sure what you're next step should be. Perhaps you could include a sample of the token you're modifying in your question? – Neil Smithline May 20 '16 at 22:07
  • 1
    @NeilSmithline ah you're right, I was using jwt.io to modify the contents, but I didn't see it is indeed modifying the signature as well. Would encrypting the token still be worthwhile if I wanted to hold sensitive information in the token? – scniro May 20 '16 at 22:29
  • Sure. I believe that JWT supports encryption natively (see example). Using that will probably be better than any home-grown solution you come up with. That said, this is going a bit out of my comfort zone. – Neil Smithline May 20 '16 at 22:35
11

I believe you are asking two questions:

  1. does changing payload invalidate signature: TL;DR: yes
  2. does adding encryption over JWT give you authenticity of content: TL;DR: don't encrypt yourself, use JWE!

Here are the answers in more detail:

(1) According to the specifications, https://www.rfc-editor.org/rfc/rfc7515.txt

the signature of a signed JWT (JWS) is computed over the protected header as well as the payload:

(see section 5.1. Message Signature or MAC Computation)

Compute the JWS Signature in the manner defined for the
       particular algorithm being used over the JWS Signing Input
       ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' ||
       BASE64URL(JWS Payload)). 

So changing the payload should invalidate the signature.

(2) Do NOT encrypt your own JWT!! There is an actual specification that defines how to encrypt JWTs (called JWE): https://www.rfc-editor.org/rfc/rfc7516.txt

JWE uses authenticated encryption which means that the plaintext is first encrypted and then an integrity check is produced over the ciphertext. You can get more info on what the plaintext looks like from Section 5.1 of above Spec.

It is possible to securely store access policies in the payload of your JWT if you use either encrypted or signed formats. You may want to use encrypted if you don't want the client or other parties to have any knowledge of the policy data. If you don't care who can read it and you only care about who can change the values, use signatures only.

Remember though that the more security you add, the bigger the performance impact so use your judgement on what is needed.

Final note: Key management of the signature and encryptions keys also becomes an important issue for you to consider, because at the end of the day, whoever has access to the keys can decrypt your JWE or modify the signature of your JWS. So make sure you use good safety practices in where you store the actual keys, who has access to them and how they are used and kept in memory.

| improve this answer | |
  • Thank you for the answer! While late, I do now agree with every point you had mentioned since I've asked this question. For my case, assuring the signature will render invalid should the token be tampered is enough for me. I no longer have the need to store sensitive information in the token, but yes, a JWE is what I would use if I did still need that! – scniro Jun 22 '17 at 18:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.