18

I'm currently learning JWT implementation with PHP and want to use JWT tokens instead of sessions for my RESTful application.

During signature creation, I'm doing something like this

token = base64Header + '.' + base64Payload + '.' + signature  

Here we are just using base64 the Payload. If I paste in sites like https://jwt.io/#debugger, the Payload gets decrypted (even if the signature is wrong).

My questions,

  1. Is JWT only for verifying the signature with server when sending data?
  2. Is insecure to keep sensitive data in Payload?
  3. If insecure, any way to secure the Payload?

Below is the sample code I wrote

<?php
    $headers = base64_encode(json_encode([
        "typ" => "JWT",
        "alg" => "HS256"
    ]));
    $claims = base64_encode(json_encode([
        "sub" => "1234567890",
        "name" => "John Doe",
        "admin" => true,
        "jti" => "870a3de5-ea7b-4062-abef-11180e530f5a",
        "iat" => 1492603378,
        "exp" => 1492606978
    ]));
    $payload = $headers.".".$claims;
    $signature = base64_encode(hash_hmac("sha256", $payload, 'secret', true));
    $encodedJWT = $payload.".".$signature;
    // eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImp0aSI6Ijg3MGEzZGU1LWVhN2ItNDA2Mi1hYmVmLTExMTgwZTUzMGY1YSIsImlhdCI6MTQ5MjYwMzM3OCwiZXhwIjoxNDkyNjA2OTc4fQ.nvw-bAUgr7H_xr3q8_Yz8rCNtMohtn2YlCmcLoLBWlc
Machavity
  • 30,841
  • 27
  • 92
  • 100
sk8terboi87 ツ
  • 3,396
  • 3
  • 34
  • 45
  • 1
    Kindly provide comments before downvoting. I'll update my question if something is not right :) – sk8terboi87 ツ Apr 19 '17 at 13:17
  • Hi, based on the info from conference I attended on JWT, sensitive data should stay in the DB and token itself should contain only info required for quick identification, not authorization. – Auris Apr 19 '17 at 13:23
  • Should we provide comments before upvoting? -:) The reason downvote comments are rare is becasuse SO moderators suggests not to due to occasional revenge downvoting. – zaph Apr 19 '17 at 13:23
  • @Auris: I read that storing data in JWT Payload helps in easy scalability when compared to database. – sk8terboi87 ツ Apr 19 '17 at 13:29
  • @zaph: You're right :) – sk8terboi87 ツ Apr 19 '17 at 13:29
  • 1
    Just an FYI, I removed the "right" verbiage in favor of asking if it's secure. The former is more opinion (and could get closed) and the latter is factual. Should still get useful answers either way – Machavity Apr 19 '17 at 13:31
  • 1
    True, storing sesitive data resolves some scalability issues, but as a tradeoff you comprmise your app security. TBH if your payload is encoded and salted + you run over https there is not much chance the data will get compromised, but you will never get this signed off by any decent pen test agency and if your client has to verify this approach there is not much chance this will get approved either. – Auris Apr 19 '17 at 13:35

3 Answers3

24

If I paste in sites like https://jwt.io/#debugger, the Payload gets decrypted (even if the signature is wrong).

Third parties cannot verify the signature because they don't have the secret key. The payload doesn't get decrypted - it gets decoded.

Ideally you should not store sensitive data in the payload since the payload is only base64 encoded and not encrypted. This means anyone who gets a hold of the token can view the contents of the payload by simply base64 decoding it.

If you have a token in local storage of a web browser and your site has an XSS vulnerability it makes it trivial to steal the token. It's bad enough that the attacker has a valid JWT (which will hopefully expire soon anyway) but if it contains sensitive data then you're in real trouble. Imagine having to notify all users on your site that they must now change various bits of sensitive data about themselves because of a potential mass compromise.

Keep the JWT lightweight. Store the users ID, their roles/grants withing the system. If you feel like you have to add sensitive data to the payload try and rethink your solution.

daviomey
  • 364
  • 3
  • 5
6
  1. Is JWT only for verifying the signature with server when sending data?

No, there is not only signed JWT (JWS - RFC 7515), but also encrypted JWT (JWE - RFC 7516).

  1. Is insecure to keep sensitive data in Payload?

When a JWT is encrypted, you can share sensitive data securely (unless the algorithm or the key are compromised).

But in your example I see no sensitive data, thus I am wondering if it is really important to use JWE in your case. I highly recommend you to read this blog post about JWT and sessions and why you should not use them for that purpose (also take a look at that part 2).

If you really want to use JWE, then I wrote a PHP library that is already able to load and create any kind of Jose (JWS/JWE) and that supports almost all algorithms from the RFC 7518 out of the box. Other libraries may exist, but there is no references list (https://jwt.io/ lists only JWS implementations).

Community
  • 1
  • 1
Spomky-Labs
  • 15,473
  • 5
  • 40
  • 64
5

As I understood, you're trying to have a complete stateless server, so you want to store even sensitive data within the token.

But your server cannot be completely stateless. Because for logout functionality, you must have either a black list or white list in order to invalidate the token. So in each request you must touch the database. If you don't have black list or white list, the tokens are still valid even when user logs out.

So, it's better to get the sensitive data from database, as you should touch your db per every request.

Vahid Najafi
  • 4,654
  • 11
  • 43
  • 88
  • 3
    Having a black or white list as you say makes it less than stateless. So it should be avoided. It would be better to just have short lived tokens so there is no 'logout' action. The logout action would just be the client deleting the token. – jfadich Apr 19 '17 at 22:25
  • 1
    Having a short expiration does not solve the issue. Specially in the mobile apps, at least you must have the option that user wants to be kept logged in. (In modern apps, users never get logged out) So you have some sort of tokens that doesn't include `exp` at all. What if user wants to logout? The token will be valid! – Vahid Najafi Apr 20 '17 at 06:18
  • 11
    Having a token without an `exp` is a very bad practice. It would be much better to have an auth token and a refresh token (this is how most google products work). The auth token is sent with every request to authorize the request but is only valid for a short time (say 30 min). The refresh token is used to get a new auth token once it expires. The refresh token should still have an expiration but it can be longer (say 2 weeks) and can be refreshed itself. To log out have the client deletes both tokens. This allows you to have users always logged in securely (just keep the fresh token secret) – jfadich Apr 20 '17 at 19:19
  • @jfadich Thats a nice tip for building a JWT in proper way. – sk8terboi87 ツ Apr 26 '17 at 03:06