Node-jsonwebtoken: Security - Token can be decoded, information can be extracted without Secret or private.key

Created on 2 Nov 2016  Â·  5Comments  Â·  Source: auth0/node-jsonwebtoken

Hi, I would be wrong or there's a major security issue I found out with this module. You can decode my signed token and get all information from it without knowing my Secret: SkyFall

Implemented on: NodeJS v6.7, jsonwebtoken
Decode service: jwt.io

Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyIkX18iOnsic3RyaWN0TW9kZSI6dHJ1ZSwic2VsZWN0ZWQiOnt9LCJnZXR0ZXJzIjp7fSwid2FzUG9wdWxhdGVkIjpmYWxzZSwiYWN0aXZlUGF0aHMiOnsicGF0aHMiOnsidXNlclBlcm1pc3Npb24iOiJpbml0IiwiX192IjoiaW5pdCIsIm5hbWUiOiJpbml0IiwiZW1haWwiOiJpbml0IiwidXNlcm5hbWUiOiJpbml0IiwiaGFzaCI6ImluaXQiLCJzYWx0IjoiaW5pdCIsImNyZWF0ZWRBdCI6ImluaXQiLCJ1cGRhdGVkQXQiOiJpbml0IiwiX2lkIjoiaW5pdCJ9LCJzdGF0ZXMiOnsiaWdub3JlIjp7fSwiZGVmYXVsdCI6e30sImluaXQiOnsiX192Ijp0cnVlLCJ1c2VyUGVybWlzc2lvbiI6dHJ1ZSwibmFtZSI6dHJ1ZSwiZW1haWwiOnRydWUsInVzZXJuYW1lIjp0cnVlLCJoYXNoIjp0cnVlLCJzYWx0Ijp0cnVlLCJjcmVhdGVkQXQiOnRydWUsInVwZGF0ZWRBdCI6dHJ1ZSwiX2lkIjp0cnVlfSwibW9kaWZ5Ijp7fSwicmVxdWlyZSI6e319LCJzdGF0ZU5hbWVzIjpbInJlcXVpcmUiLCJtb2RpZnkiLCJpbml0IiwiZGVmYXVsdCIsImlnbm9yZSJdfSwiZW1pdHRlciI6eyJkb21haW4iOm51bGwsIl9ldmVudHMiOnt9LCJfZXZlbnRzQ291bnQiOjAsIl9tYXhMaXN0ZW5lcnMiOjB9fSwiaXNOZXciOmZhbHNlLCJfZG9jIjp7InVzZXJQZXJtaXNzaW9uIjoidXNlciIsImZhY2Vib29rIjp7fSwiX192IjowLCJuYW1lIjoiU2FtIiwiZW1haWwiOiJXYWx0ZXJAcmVjcGljLmNvbSIsInVzZXJuYW1lIjoiU2FtIiwiaGFzaCI6ImU5YTM4ZTliYjBkYTFlOTgxNzU2YjE0MWI4YmM5MWUxNTI4NzYwMmU5YTZmODAzZWUwZWViMmI3MzgxMjkwODllODVlYmVkY2FkNGVhMjg4MWQ4ZWQ2N2E2NTk4MTQzZWU2YjFlOGI2Nzg2OWY4ZTJkMDIwMzgyZGFiMDFkMzczYWM4MDhmMzVlMDcyYTM2MTgzMGQ2YTgwZWIzMWQ0MzNlNjg0NGY0YmEwMWViOGFlOTRmM2ViOTQ1NWRhNGRmOTVkNmU1OGU0OTAxZDBiYTBlMWU2ZTUyMzY5MzYxMTU1MDA2NTYwYmMyMzc1NTQwZDUyYWRiODk4ZjViYWY3NTdlNzE0ZTcwOTBjMjA2MWY5MmJiNGM5MDY0ZGM5ZTMyOWZiMmU0MjY4MTY1ZTFkMWQyNjk1OGIzNDQzNzVjMjA1ODZiY2UxY2JmZjEzYTE2MjliYzNmOGMyZmNhYjUwODQ2NjA1ZTVjYjFjMzVhYWM4N2ZhNzkzZTUzMTIzYTMyNTZiNTcxMzhlZWU4ZDNhNzZmOWU5MjA5NmVkM2U2YjY1OGQwNDQ0YTgzNjM0ZjRjYjQ5YjMxNDYwMmM0MTg0ODg4MTMzMDJjYWFiZGJhYmNmZmZiMDkxNTI5ZGI3NGYwM2Y2ZDE5OTE0MmYxOWFmMzUxZTYxZjM1ZDVkMDVmNTZjNDU4NjcyY2E5ZTU3ODAxZDZhYmZkYTE2YTU0ZGI2MjkxNjI3ZGM1MGYzZWQyZDllYjYzOWE4N2ZhMDI5N2U2NjE4ZTdiZmRjODM2MTNjMTUwN2JmZWQ3NWExMWNkZmY2YjcyYjUwODc2MTZiMzg1Yzk3YTExNDUwNjI3NDVkODFkMDUxMDRiZDg2Y2EwMDE4M2NjMGIyNjQyYzAxN2JiN2VhMDJhZTBhNTJiYmY0ZWYxYWNjYTMxNzcwOGYzYTdhYmUxODU3MzQ3ZTBhMjRmZjAyZWJmZGVjNjdmMDJiMmNlMmY0MjU2ODYyNjgzOWZjZmE1ZDgxODBmM2E0MTUxMDVlNWFmODA5MmM3ZTc1ZjEzOGZhM2MzOGM3MmQwMjE5OTBkMWZlYmU2YjQ5MjQ4YmVlYTRiM2QwZDQxYjQ4YWY3MGM1MDAyMmZhMTg0NjY5ZDljMDhlOTNlNmNlYWExMzY4YTgzOGU4NmUyZWZhZTBiNzc4ZGE5NmNhMmM5OTc0MjQ1MjYwODlkNjgzNjM3ZGFmMTg4ZjIwN2EyMmNlYjc4MWQ3YTUxMTQ3ZjkyZTQ2MzViNGUxYjc1YzkyMzM2YzE0YjFhMDMxN2JjODNlYTc0ZTBhMmY4Y2NjMDIzMmVhNzBlZmVjZWE3NjNiMzIwZjZiNWY0MTFjMWM0OTczNDMiLCJzYWx0IjoiODM1YjQyZDQzNWZhNzU4ZGJhN2FiMGQwMzJlYzdjNWU4MjNiNzlmNTBlMWMxMzdkZWNlZWY5YzQxNjNmNDEzNCIsImNyZWF0ZWRBdCI6IjIwMTYtMTAtMTdUMDI6MTA6NTUuNTkxWiIsInVwZGF0ZWRBdCI6IjIwMTYtMTAtMTdUMDI6MTA6NTUuNTkxWiIsIl9pZCI6IjU4MDQzMzJmMTM0NmZiMWIyNDk4NTY3YiJ9LCJfcHJlcyI6eyIkX19vcmlnaW5hbF9zYXZlIjpbbnVsbCxudWxsLG51bGwsbnVsbF0sIiRfX29yaWdpbmFsX3ZhbGlkYXRlIjpbbnVsbF0sIiRfX29yaWdpbmFsX3JlbW92ZSI6W251bGxdfSwiX3Bvc3RzIjp7IiRfX29yaWdpbmFsX3NhdmUiOltdLCIkX19vcmlnaW5hbF92YWxpZGF0ZSI6W10sIiRfX29yaWdpbmFsX3JlbW92ZSI6W119LCJpYXQiOjE0NzgwNzg4MTcsImV4cCI6MTQ3ODA3OTExN30.JFSSHB5G0Jdxh_kWqoZuzilgIMa_9jllkI6A-V1Bdxo

How I sign it:
jwt.sign(user, process.env.JWT_SECRET, { expiresIn: parseInt(process.env.SESSION_TIMER) })
How I verify it:
jwt.verify (token, process.env.JWT_SECRET, function (err, decoded) {})

I even tried it with a private.key but you still can get the content of the token without private.key file.
Token: eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyIkX18iOnsic3RyaWN0TW9kZSI6dHJ1ZSwic2VsZWN0ZWQiOnt9LCJnZXR0ZXJzIjp7fSwid2FzUG9wdWxhdGVkIjpmYWxzZSwiYWN0aXZlUGF0aHMiOnsicGF0aHMiOnsidXNlclBlcm1pc3Npb24iOiJpbml0IiwiX192IjoiaW5pdCIsIm5hbWUiOiJpbml0IiwiZW1haWwiOiJpbml0IiwidXNlcm5hbWUiOiJpbml0IiwiaGFzaCI6ImluaXQiLCJzYWx0IjoiaW5pdCIsImNyZWF0ZWRBdCI6ImluaXQiLCJ1cGRhdGVkQXQiOiJpbml0IiwiX2lkIjoiaW5pdCJ9LCJzdGF0ZXMiOnsiaWdub3JlIjp7fSwiZGVmYXVsdCI6e30sImluaXQiOnsiX192Ijp0cnVlLCJ1c2VyUGVybWlzc2lvbiI6dHJ1ZSwibmFtZSI6dHJ1ZSwiZW1haWwiOnRydWUsInVzZXJuYW1lIjp0cnVlLCJoYXNoIjp0cnVlLCJzYWx0Ijp0cnVlLCJjcmVhdGVkQXQiOnRydWUsInVwZGF0ZWRBdCI6dHJ1ZSwiX2lkIjp0cnVlfSwibW9kaWZ5Ijp7fSwicmVxdWlyZSI6e319LCJzdGF0ZU5hbWVzIjpbInJlcXVpcmUiLCJtb2RpZnkiLCJpbml0IiwiZGVmYXVsdCIsImlnbm9yZSJdfSwiZW1pdHRlciI6eyJkb21haW4iOm51bGwsIl9ldmVudHMiOnt9LCJfZXZlbnRzQ291bnQiOjAsIl9tYXhMaXN0ZW5lcnMiOjB9fSwiaXNOZXciOmZhbHNlLCJfZG9jIjp7InVzZXJQZXJtaXNzaW9uIjoidXNlciIsImZhY2Vib29rIjp7fSwiX192IjowLCJuYW1lIjoiU2FtIiwiZW1haWwiOiJXYWx0ZXJAcmVjcGljLmNvbSIsInVzZXJuYW1lIjoiU2FtIiwiaGFzaCI6ImU5YTM4ZTliYjBkYTFlOTgxNzU2YjE0MWI4YmM5MWUxNTI4NzYwMmU5YTZmODAzZWUwZWViMmI3MzgxMjkwODllODVlYmVkY2FkNGVhMjg4MWQ4ZWQ2N2E2NTk4MTQzZWU2YjFlOGI2Nzg2OWY4ZTJkMDIwMzgyZGFiMDFkMzczYWM4MDhmMzVlMDcyYTM2MTgzMGQ2YTgwZWIzMWQ0MzNlNjg0NGY0YmEwMWViOGFlOTRmM2ViOTQ1NWRhNGRmOTVkNmU1OGU0OTAxZDBiYTBlMWU2ZTUyMzY5MzYxMTU1MDA2NTYwYmMyMzc1NTQwZDUyYWRiODk4ZjViYWY3NTdlNzE0ZTcwOTBjMjA2MWY5MmJiNGM5MDY0ZGM5ZTMyOWZiMmU0MjY4MTY1ZTFkMWQyNjk1OGIzNDQzNzVjMjA1ODZiY2UxY2JmZjEzYTE2MjliYzNmOGMyZmNhYjUwODQ2NjA1ZTVjYjFjMzVhYWM4N2ZhNzkzZTUzMTIzYTMyNTZiNTcxMzhlZWU4ZDNhNzZmOWU5MjA5NmVkM2U2YjY1OGQwNDQ0YTgzNjM0ZjRjYjQ5YjMxNDYwMmM0MTg0ODg4MTMzMDJjYWFiZGJhYmNmZmZiMDkxNTI5ZGI3NGYwM2Y2ZDE5OTE0MmYxOWFmMzUxZTYxZjM1ZDVkMDVmNTZjNDU4NjcyY2E5ZTU3ODAxZDZhYmZkYTE2YTU0ZGI2MjkxNjI3ZGM1MGYzZWQyZDllYjYzOWE4N2ZhMDI5N2U2NjE4ZTdiZmRjODM2MTNjMTUwN2JmZWQ3NWExMWNkZmY2YjcyYjUwODc2MTZiMzg1Yzk3YTExNDUwNjI3NDVkODFkMDUxMDRiZDg2Y2EwMDE4M2NjMGIyNjQyYzAxN2JiN2VhMDJhZTBhNTJiYmY0ZWYxYWNjYTMxNzcwOGYzYTdhYmUxODU3MzQ3ZTBhMjRmZjAyZWJmZGVjNjdmMDJiMmNlMmY0MjU2ODYyNjgzOWZjZmE1ZDgxODBmM2E0MTUxMDVlNWFmODA5MmM3ZTc1ZjEzOGZhM2MzOGM3MmQwMjE5OTBkMWZlYmU2YjQ5MjQ4YmVlYTRiM2QwZDQxYjQ4YWY3MGM1MDAyMmZhMTg0NjY5ZDljMDhlOTNlNmNlYWExMzY4YTgzOGU4NmUyZWZhZTBiNzc4ZGE5NmNhMmM5OTc0MjQ1MjYwODlkNjgzNjM3ZGFmMTg4ZjIwN2EyMmNlYjc4MWQ3YTUxMTQ3ZjkyZTQ2MzViNGUxYjc1YzkyMzM2YzE0YjFhMDMxN2JjODNlYTc0ZTBhMmY4Y2NjMDIzMmVhNzBlZmVjZWE3NjNiMzIwZjZiNWY0MTFjMWM0OTczNDMiLCJzYWx0IjoiODM1YjQyZDQzNWZhNzU4ZGJhN2FiMGQwMzJlYzdjNWU4MjNiNzlmNTBlMWMxMzdkZWNlZWY5YzQxNjNmNDEzNCIsImNyZWF0ZWRBdCI6IjIwMTYtMTAtMTdUMDI6MTA6NTUuNTkxWiIsInVwZGF0ZWRBdCI6IjIwMTYtMTAtMTdUMDI6MTA6NTUuNTkxWiIsIl9pZCI6IjU4MDQzMzJmMTM0NmZiMWIyNDk4NTY3YiJ9LCJfcHJlcyI6eyIkX19vcmlnaW5hbF9zYXZlIjpbbnVsbCxudWxsLG51bGwsbnVsbF0sIiRfX29yaWdpbmFsX3ZhbGlkYXRlIjpbbnVsbF0sIiRfX29yaWdpbmFsX3JlbW92ZSI6W251bGxdfSwiX3Bvc3RzIjp7IiRfX29yaWdpbmFsX3NhdmUiOltdLCIkX19vcmlnaW5hbF92YWxpZGF0ZSI6W10sIiRfX29yaWdpbmFsX3JlbW92ZSI6W119LCJpYXQiOjE0NzgwNzkyNzgsImV4cCI6MTQ3ODA3OTU3OH0.I-SxubNLGPXYLtrxPSmxBPIbV_FE5WThwdthx0jXWW5OfADn-Ew27kgqCAOpeX41JWYbjA1CiJOU6pHJakt5toRrQF1g4XSU7nTOIhOaR2wn7cZ1cQZnjrxp-Vb_tr0BP1rAMHAuAWcAIZAj6kuietHuV_6FXDVKMB4sp9-vDEM

How I sign it:
jwt.sign(user, cert, { expiresIn: parseInt(process.env.SESSION_TIMER), algorithm: 'RS512' })

How I verify it:
jwt.verify (token, cert, function (err, decoded) {})

Please tell me I am wrong at some point, I really love the concept of JWT - so easy (and effective) to maintain sessions as well as tracking user data.

Thanks, Sam

Most helpful comment

JWT (at least by default, I think it is possible to encrypt the payload) does not encrypt the payload of your token, it just adds a signature so you can verify (with the secret) that the contents are not edited by some third party.

All 5 comments

JWT (at least by default, I think it is possible to encrypt the payload) does not encrypt the payload of your token, it just adds a signature so you can verify (with the secret) that the contents are not edited by some third party.

I was under the same impression as @nickschot. I only store permissions and the user's unique ID inside of the token, so even if it's decrypted the info is pretty much useless as they can't verify the signature without knowing the secret key it was originally signed with. I do know that some people choose to encrypt the payload, I've just never had the need to.

See here: http://softwareengineering.stackexchange.com/questions/280257/json-web-token-why-is-the-payload-public

@nickschot , @mitchellporter: thank you for your message. I think that's the way jwt is.
@jfromaniello : I can see quite a lot traction from Google on this issue that developers want to have payload encrypted. Could you please consider to add this as a new feature?
And awesome job on jwt implementation by the way, super easy to use, nicely get the thing done. Thanks @jfromaniello and the team for your hard work!

@samsontr If you need it encrypted (not just signed and encoded), you want a JWE, JSON Web Encryption. It's not supported in this package but available in e.g. https://github.com/square/js-jose
Normally though, I'd say that's unnecessary…

@fiddur thank you for your suggestion. It is helpful.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

p-brighenti picture p-brighenti  Â·  4Comments

usamamashkoor picture usamamashkoor  Â·  4Comments

samholmes picture samholmes  Â·  5Comments

shea256 picture shea256  Â·  3Comments

cope picture cope  Â·  4Comments