update tests, updated qldoc and examples, upgrade all libraries to path-problem, update jsonwebtoken source and sinks

This commit is contained in:
amammad
2023-11-07 08:25:25 +01:00
parent a9c8bc082f
commit 0652afced3
22 changed files with 521 additions and 195 deletions

View File

@@ -1,45 +0,0 @@
const express = require('express')
const app = express()
const jwtJsonwebtoken = require('jsonwebtoken');
const {getSecret} = require('./Config.js');
const jwt_decode = require('jwt-decode');
const jwt_simple = require('jwt-simple');
const jose = require('jose')
const port = 3000
async function startSymmetric(token) {
const {payload, protectedHeader} = await jose.jwtVerify(token, new TextEncoder().encode(getSecret()))
return {
payload, protectedHeader
}
}
app.get('/', (req, res) => {
const UserToken = req.headers.authorization;
// BAD: no verification
jwtJsonwebtoken.decode(UserToken)
// GOOD: use verify alone or use as a check,
// sometimes it seems some coders use both for same token
const UserToken2 = req.headers.authorization;
jwtJsonwebtoken.decode(UserToken2)
jwtJsonwebtoken.verify(UserToken2, getSecret())
// jwt-decode
// BAD: no verification
jwt_decode(UserToken)
// jose
// BAD: no verification
jose.decodeJwt(UserToken)
// GOOD
startSymmetric(UserToken).then(result => console.log(result))
// jwt-simple
// no verification
jwt_simple.decode(UserToken, getSecret(), true);
// GOOD
jwt_simple.decode(UserToken, getSecret(), false);
jwt_simple.decode(UserToken, getSecret());
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})

View File

@@ -0,0 +1,39 @@
const express = require('express')
const app = express()
const jwtJsonwebtoken = require('jsonwebtoken');
const jwt_decode = require('jwt-decode');
const jwt_simple = require('jwt-simple');
const jose = require('jose')
const port = 3000
function getSecret() {
return "A Safe generated random key"
}
app.get('/jose', (req, res) => {
const UserToken = req.headers.authorization;
// BAD: no signature verification
jose.decodeJwt(UserToken)
})
app.get('/jwtDecode', (req, res) => {
const UserToken = req.headers.authorization;
// BAD: no signature verification
jwt_decode(UserToken)
})
app.get('/jwtSimple', (req, res) => {
const UserToken = req.headers.authorization;
// jwt.decode(token, key, noVerify, algorithm)
// BAD: no signature verification
jwt_simple.decode(UserToken, getSecret(), true);
})
app.get('/jwtJsonwebtoken', (req, res) => {
const UserToken = req.headers.authorization;
// BAD: no signature verification
jwtJsonwebtoken.decode(UserToken)
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})

View File

@@ -0,0 +1,56 @@
const express = require('express')
const app = express()
const jwtJsonwebtoken = require('jsonwebtoken');
const jwt_decode = require('jwt-decode');
const jwt_simple = require('jwt-simple');
const jose = require('jose')
const port = 3000
function getSecret() {
return "A Safe generated random key"
}
app.get('/jose1', async (req, res) => {
const UserToken = req.headers.authorization;
// GOOD: with signature verification
await jose.jwtVerify(UserToken, new TextEncoder().encode(getSecret()))
})
app.get('/jose2', async (req, res) => {
const UserToken = req.headers.authorization;
// GOOD: first without signature verification then with signature verification for same UserToken
jose.decodeJwt(UserToken)
await jose.jwtVerify(UserToken, new TextEncoder().encode(getSecret()))
})
app.get('/jwtSimple1', (req, res) => {
const UserToken = req.headers.authorization;
// GOOD: first without signature verification then with signature verification for same UserToken
jwt_simple.decode(UserToken, getSecret(), false);
jwt_simple.decode(UserToken, getSecret());
})
app.get('/jwtSimple2', (req, res) => {
const UserToken = req.headers.authorization;
// GOOD: with signature verification
jwt_simple.decode(UserToken, getSecret(), true);
jwt_simple.decode(UserToken, getSecret());
})
app.get('/jwtJsonwebtoken1', (req, res) => {
const UserToken = req.headers.authorization;
// GOOD: with signature verification
jwtJsonwebtoken.verify(UserToken, getSecret())
})
app.get('/jwtJsonwebtoken2', (req, res) => {
const UserToken = req.headers.authorization;
// GOOD: first without signature verification then with signature verification for same UserToken
jwtJsonwebtoken.decode(UserToken)
jwtJsonwebtoken.verify(UserToken, getSecret())
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})

View File

@@ -15,14 +15,35 @@ import DataFlow::PathGraph
DataFlow::Node unverifiedDecode() {
result = API::moduleImport("jsonwebtoken").getMember("decode").getParameter(0).asSink()
or
exists(API::Node verify | verify = API::moduleImport("jsonwebtoken").getMember("verify") |
verify
.getParameter(2)
.getMember("algorithms")
.getUnknownMember()
.asSink()
.mayHaveStringValue("none") and
result = verify.getParameter(0).asSink()
)
}
DataFlow::Node verifiedDecode() {
result = API::moduleImport("jsonwebtoken").getMember("verify").getParameter(0).asSink()
exists(API::Node verify | verify = API::moduleImport("jsonwebtoken").getMember("verify") |
(
not verify
.getParameter(2)
.getMember("algorithms")
.getUnknownMember()
.asSink()
.mayHaveStringValue("none") or
not exists(verify.getParameter(2).getMember("algorithms"))
) and
result = verify.getParameter(0).asSink()
)
}
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "jsonwebtoken constant secret key" }
Configuration() { this = "jsonwebtoken without any signature verification" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
@@ -37,11 +58,8 @@ from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where
cfg.hasFlowPath(source, sink) and
sink.getNode() = unverifiedDecode() and
not isSafe(source.getNode())
not exists(Configuration cfg2 |
cfg2.hasFlowPath(source, any(DataFlow::SinkPathNode n | n.getNode() = verifiedDecode()))
)
select source.getNode(), source, sink, "Decoding JWT $@.", sink.getNode(),
"without signature verification"
// Holds if the source has a flow to a JWT decoding function with signature verification
predicate isSafe(DataFlow::Node source) {
exists(Configuration cfg | cfg.hasFlow(source, verifiedDecode()))
}

View File

@@ -1,7 +1,7 @@
/**
* @name JWT missing secret or public key verification
* @description The application does not verify the JWT payload with a cryptographic secret or public key.
* @kind problem
* @kind path-problem
* @problem.severity error
* @security-severity 8.0
* @precision high
@@ -11,7 +11,34 @@
*/
import javascript
import DataFlow::PathGraph
from DataFlow::Node sink
where sink = API::moduleImport("jose").getMember("decodeJwt").getParameter(0).asSink()
select sink, "This Token is Decoded in without signature validation"
DataFlow::Node unverifiedDecode() {
result = API::moduleImport("jose").getMember("decodeJwt").getParameter(0).asSink()
}
DataFlow::Node verifiedDecode() {
result = API::moduleImport("jose").getMember("jwtVerify").getParameter(0).asSink()
}
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "jsonwebtoken without any signature verification" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
sink = unverifiedDecode()
or
sink = verifiedDecode()
}
}
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where
cfg.hasFlowPath(source, sink) and
sink.getNode() = unverifiedDecode() and
not exists(Configuration cfg2 |
cfg2.hasFlowPath(source, any(DataFlow::SinkPathNode n | n.getNode() = verifiedDecode()))
)
select source.getNode(), source, sink, "Decoding JWT $@.", sink.getNode(),
"without signature verification"

View File

@@ -1,7 +1,7 @@
/**
* @name JWT missing secret or public key verification
* @description The application does not verify the JWT payload with a cryptographic secret or public key.
* @kind problem
* @kind path-problem
* @problem.severity error
* @security-severity 8.0
* @precision high
@@ -11,9 +11,21 @@
*/
import javascript
import DataFlow::PathGraph
from DataFlow::Node sink
where
// I must somehow check that following is implemented in server not browser
sink = API::moduleImport("jwt-decode").getParameter(0).asSink()
select sink, "This Token is Decoded in without signature validation"
DataFlow::Node unverifiedDecode() {
result = API::moduleImport("jwt-decode").getParameter(0).asSink()
}
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "jsonwebtoken without any signature verification" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink = unverifiedDecode() }
}
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select source.getNode(), source, sink, "Decoding JWT $@.", sink.getNode(),
"without signature verification"

View File

@@ -19,15 +19,18 @@
<example>
<p>
The following code you can see an Example from a popular Library.
In the following code, you can see the proper usage of the most popular JWT libraries.
</p>
<sample src="Examples/Good.js" />
<sample src="Example.js" />
<p>
In the following code, you can see the improper usage of the most popular JWT libraries.
</p>
<sample src="Examples/Bad.js" />
</example>
<references>
<li>
<a href="https://www.ghostccamm.com/blog/multi_strapi_vulns/#cve-2023-22893-authentication-bypass-for-aws-cognito-login-provider-in-strapi-versions-456">JWT claim had not been verified</a>
<a href="https://www.ghostccamm.com/blog/multi_strapi_vulns/#cve-2023-22893-authentication-bypass-for-aws-cognito-login-provider-in-strapi-versions-456">JWT claim has not been verified</a>
</li>
</references>

View File

@@ -1,21 +1,53 @@
/**
* @name JWT missing secret or public key verification
* @description The application does not verify the JWT payload with a cryptographic secret or public key.
* @kind problem
* @kind path-problem
* @problem.severity error
* @security-severity 8.0
* @precision high
* @id js/jwt-missing-verification
* @id js/jwt-missing-verification-jwt-simple
* @tags security
* external/cwe/cwe-347
*/
import javascript
import DataFlow::PathGraph
from DataFlow::Node sink
where
DataFlow::Node unverifiedDecode() {
exists(API::Node n | n = API::moduleImport("jwt-simple").getMember("decode") |
n.getParameter(2).asSink().asExpr() = any(BoolLiteral b | b.getBoolValue() = true) and
sink = n.getParameter(0).asSink()
result = n.getParameter(0).asSink()
)
select sink, "This Token is Decoded in without signature validation"
}
DataFlow::Node verifiedDecode() {
exists(API::Node n | n = API::moduleImport("jwt-simple").getMember("decode") |
(
n.getParameter(2).asSink().asExpr() = any(BoolLiteral b | b.getBoolValue() = false) or
not exists(n.getParameter(2))
) and
result = n.getParameter(0).asSink()
)
}
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "jsonwebtoken without any signature verification" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
sink = unverifiedDecode()
or
sink = verifiedDecode()
}
}
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where
cfg.hasFlowPath(source, sink) and
sink.getNode() = unverifiedDecode() and
not exists(Configuration cfg2 |
cfg2.hasFlowPath(source, any(DataFlow::SinkPathNode n | n.getNode() = verifiedDecode()))
)
select source.getNode(), source, sink, "Decoding JWT $@.", sink.getNode(),
"without signature verification"

View File

@@ -0,0 +1,63 @@
nodes
| JsonWebToken.js:13:11:13:47 | UserToken |
| JsonWebToken.js:13:23:13:47 | req.hea ... ization |
| JsonWebToken.js:13:23:13:47 | req.hea ... ization |
| JsonWebToken.js:16:28:16:36 | UserToken |
| JsonWebToken.js:16:28:16:36 | UserToken |
| JsonWebToken.js:20:11:20:47 | UserToken |
| JsonWebToken.js:20:23:20:47 | req.hea ... ization |
| JsonWebToken.js:20:23:20:47 | req.hea ... ization |
| JsonWebToken.js:23:28:23:36 | UserToken |
| JsonWebToken.js:23:28:23:36 | UserToken |
| JsonWebToken.js:24:28:24:36 | UserToken |
| JsonWebToken.js:24:28:24:36 | UserToken |
| JsonWebToken.js:28:11:28:47 | UserToken |
| JsonWebToken.js:28:23:28:47 | req.hea ... ization |
| JsonWebToken.js:28:23:28:47 | req.hea ... ization |
| JsonWebToken.js:31:28:31:36 | UserToken |
| JsonWebToken.js:31:28:31:36 | UserToken |
| JsonWebToken.js:35:11:35:47 | UserToken |
| JsonWebToken.js:35:23:35:47 | req.hea ... ization |
| JsonWebToken.js:35:23:35:47 | req.hea ... ization |
| JsonWebToken.js:38:28:38:36 | UserToken |
| JsonWebToken.js:38:28:38:36 | UserToken |
| JsonWebToken.js:39:28:39:36 | UserToken |
| JsonWebToken.js:39:28:39:36 | UserToken |
| JsonWebToken.js:43:11:43:47 | UserToken |
| JsonWebToken.js:43:23:43:47 | req.hea ... ization |
| JsonWebToken.js:43:23:43:47 | req.hea ... ization |
| JsonWebToken.js:46:28:46:36 | UserToken |
| JsonWebToken.js:46:28:46:36 | UserToken |
| JsonWebToken.js:47:28:47:36 | UserToken |
| JsonWebToken.js:47:28:47:36 | UserToken |
edges
| JsonWebToken.js:13:11:13:47 | UserToken | JsonWebToken.js:16:28:16:36 | UserToken |
| JsonWebToken.js:13:11:13:47 | UserToken | JsonWebToken.js:16:28:16:36 | UserToken |
| JsonWebToken.js:13:23:13:47 | req.hea ... ization | JsonWebToken.js:13:11:13:47 | UserToken |
| JsonWebToken.js:13:23:13:47 | req.hea ... ization | JsonWebToken.js:13:11:13:47 | UserToken |
| JsonWebToken.js:20:11:20:47 | UserToken | JsonWebToken.js:23:28:23:36 | UserToken |
| JsonWebToken.js:20:11:20:47 | UserToken | JsonWebToken.js:23:28:23:36 | UserToken |
| JsonWebToken.js:20:11:20:47 | UserToken | JsonWebToken.js:24:28:24:36 | UserToken |
| JsonWebToken.js:20:11:20:47 | UserToken | JsonWebToken.js:24:28:24:36 | UserToken |
| JsonWebToken.js:20:23:20:47 | req.hea ... ization | JsonWebToken.js:20:11:20:47 | UserToken |
| JsonWebToken.js:20:23:20:47 | req.hea ... ization | JsonWebToken.js:20:11:20:47 | UserToken |
| JsonWebToken.js:28:11:28:47 | UserToken | JsonWebToken.js:31:28:31:36 | UserToken |
| JsonWebToken.js:28:11:28:47 | UserToken | JsonWebToken.js:31:28:31:36 | UserToken |
| JsonWebToken.js:28:23:28:47 | req.hea ... ization | JsonWebToken.js:28:11:28:47 | UserToken |
| JsonWebToken.js:28:23:28:47 | req.hea ... ization | JsonWebToken.js:28:11:28:47 | UserToken |
| JsonWebToken.js:35:11:35:47 | UserToken | JsonWebToken.js:38:28:38:36 | UserToken |
| JsonWebToken.js:35:11:35:47 | UserToken | JsonWebToken.js:38:28:38:36 | UserToken |
| JsonWebToken.js:35:11:35:47 | UserToken | JsonWebToken.js:39:28:39:36 | UserToken |
| JsonWebToken.js:35:11:35:47 | UserToken | JsonWebToken.js:39:28:39:36 | UserToken |
| JsonWebToken.js:35:23:35:47 | req.hea ... ization | JsonWebToken.js:35:11:35:47 | UserToken |
| JsonWebToken.js:35:23:35:47 | req.hea ... ization | JsonWebToken.js:35:11:35:47 | UserToken |
| JsonWebToken.js:43:11:43:47 | UserToken | JsonWebToken.js:46:28:46:36 | UserToken |
| JsonWebToken.js:43:11:43:47 | UserToken | JsonWebToken.js:46:28:46:36 | UserToken |
| JsonWebToken.js:43:11:43:47 | UserToken | JsonWebToken.js:47:28:47:36 | UserToken |
| JsonWebToken.js:43:11:43:47 | UserToken | JsonWebToken.js:47:28:47:36 | UserToken |
| JsonWebToken.js:43:23:43:47 | req.hea ... ization | JsonWebToken.js:43:11:43:47 | UserToken |
| JsonWebToken.js:43:23:43:47 | req.hea ... ization | JsonWebToken.js:43:11:43:47 | UserToken |
#select
| JsonWebToken.js:13:23:13:47 | req.hea ... ization | JsonWebToken.js:13:23:13:47 | req.hea ... ization | JsonWebToken.js:16:28:16:36 | UserToken | Decoding JWT $@. | JsonWebToken.js:16:28:16:36 | UserToken | without signature verification |
| JsonWebToken.js:20:23:20:47 | req.hea ... ization | JsonWebToken.js:20:23:20:47 | req.hea ... ization | JsonWebToken.js:23:28:23:36 | UserToken | Decoding JWT $@. | JsonWebToken.js:23:28:23:36 | UserToken | without signature verification |
| JsonWebToken.js:20:23:20:47 | req.hea ... ization | JsonWebToken.js:20:23:20:47 | req.hea ... ization | JsonWebToken.js:24:28:24:36 | UserToken | Decoding JWT $@. | JsonWebToken.js:24:28:24:36 | UserToken | without signature verification |

View File

@@ -0,0 +1,52 @@
const express = require('express')
const app = express()
const jwtJsonwebtoken = require('jsonwebtoken');
const jwt_decode = require('jwt-decode');
const jwt_simple = require('jwt-simple');
const jose = require('jose')
const port = 3000
function getSecret() {
return "A Safe generated random key"
}
app.get('/jwtJsonwebtoken1', (req, res) => {
const UserToken = req.headers.authorization;
// BAD: no signature verification
jwtJsonwebtoken.decode(UserToken)
})
app.get('/jwtJsonwebtoken2', (req, res) => {
const UserToken = req.headers.authorization;
// BAD: no signature verification
jwtJsonwebtoken.decode(UserToken)
jwtJsonwebtoken.verify(UserToken, getSecret(), { algorithms: ["HS256", "none"] })
})
app.get('/jwtJsonwebtoken3', (req, res) => {
const UserToken = req.headers.authorization;
// GOOD: with signature verification
jwtJsonwebtoken.verify(UserToken, getSecret())
})
app.get('/jwtJsonwebtoken4', (req, res) => {
const UserToken = req.headers.authorization;
// GOOD: first without signature verification then with signature verification for same UserToken
jwtJsonwebtoken.decode(UserToken)
jwtJsonwebtoken.verify(UserToken, getSecret())
})
app.get('/jwtJsonwebtoken5', (req, res) => {
const UserToken = req.headers.authorization;
// GOOD: first without signature verification then with signature verification for same UserToken
jwtJsonwebtoken.decode(UserToken)
jwtJsonwebtoken.verify(UserToken, getSecret(), { algorithms: ["HS256"] })
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})

View File

@@ -1,84 +0,0 @@
const express = require('express')
const app = express()
const jwtJsonwebtoken = require('jsonwebtoken');
const { getSecret } = require('./Config.js');
const jwt_decode = require('jwt-decode');
const jwt_simple = require('jwt-simple');
const jose = require('jose')
const port = 3000
async function startSymmetric(token) {
const { payload, protectedHeader } = await jose.jwtVerify(token, new TextEncoder().encode(getSecret()))
return {
payload, protectedHeader
}
}
app.get('/jose', (req, res) => {
const UserToken = req.headers.authorization;
// jose
jose.decodeJwt(UserToken) // NOT OK: no signature verification
startSymmetric(UserToken).then(result => console.log(result)) // OK: with signature verification
})
app.get('/jwtDecode', (req, res) => {
const UserToken = req.headers.authorization;
// jwt-decode
jwt_decode(UserToken) // NOT OK: no signature verification
})
app.get('/jwtSimple', (req, res) => {
const UserToken = req.headers.authorization;
// jwt-simple
// jwt.decode(token, key, noVerify, algorithm)
jwt_simple.decode(UserToken, getSecret(), true); // NOT OK: no signature verification
})
app.get('/jwtSimple2', (req, res) => {
const UserToken = req.headers.authorization;
// jwt-simple
// jwt.decode(token, key, noVerify, algorithm)
jwt_simple.decode(UserToken, getSecret(), false); // OK: with signature verification
jwt_simple.decode(UserToken, getSecret()); // OK: with signature verification
})
app.get('/jwtSimple3', (req, res) => {
const UserToken = req.headers.authorization;
// jwt-simple
// jwt.decode(token, key, noVerify, algorithm)
jwt_simple.decode(UserToken, getSecret(), true); // OK: verify the signature of same token in next line
jwt_simple.decode(UserToken, getSecret()); // OK
})
app.get('/jwtJsonwebtoken', (req, res) => {
const UserToken = req.headers.authorization;
jwtJsonwebtoken.decode(UserToken) // NOT OK: no signature verification
jwtJsonwebtoken.verify(UserToken, false, { algorithms: ["HS256", "none"] }) // NOT OK: no signature verification
})
app.get('/jwtJsonwebtoken2', (req, res) => {
const UserToken = req.headers.authorization;
jwtJsonwebtoken.verify(UserToken, getSecret()) // OK: with signature verification
})
app.get('/jwtJsonwebtoken3', (req, res) => {
const UserToken = req.headers.authorization;
jwtJsonwebtoken.decode(UserToken) // OK: verify the signature of same token in next line
jwtJsonwebtoken.verify(UserToken, getSecret()) // OK
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})

View File

@@ -0,0 +1,35 @@
nodes
| jose.js:14:11:14:47 | UserToken |
| jose.js:14:23:14:47 | req.hea ... ization |
| jose.js:14:23:14:47 | req.hea ... ization |
| jose.js:16:20:16:28 | UserToken |
| jose.js:16:20:16:28 | UserToken |
| jose.js:21:11:21:47 | UserToken |
| jose.js:21:23:21:47 | req.hea ... ization |
| jose.js:21:23:21:47 | req.hea ... ization |
| jose.js:23:26:23:34 | UserToken |
| jose.js:23:26:23:34 | UserToken |
| jose.js:27:11:27:47 | UserToken |
| jose.js:27:23:27:47 | req.hea ... ization |
| jose.js:27:23:27:47 | req.hea ... ization |
| jose.js:29:20:29:28 | UserToken |
| jose.js:29:20:29:28 | UserToken |
| jose.js:30:26:30:34 | UserToken |
| jose.js:30:26:30:34 | UserToken |
edges
| jose.js:14:11:14:47 | UserToken | jose.js:16:20:16:28 | UserToken |
| jose.js:14:11:14:47 | UserToken | jose.js:16:20:16:28 | UserToken |
| jose.js:14:23:14:47 | req.hea ... ization | jose.js:14:11:14:47 | UserToken |
| jose.js:14:23:14:47 | req.hea ... ization | jose.js:14:11:14:47 | UserToken |
| jose.js:21:11:21:47 | UserToken | jose.js:23:26:23:34 | UserToken |
| jose.js:21:11:21:47 | UserToken | jose.js:23:26:23:34 | UserToken |
| jose.js:21:23:21:47 | req.hea ... ization | jose.js:21:11:21:47 | UserToken |
| jose.js:21:23:21:47 | req.hea ... ization | jose.js:21:11:21:47 | UserToken |
| jose.js:27:11:27:47 | UserToken | jose.js:29:20:29:28 | UserToken |
| jose.js:27:11:27:47 | UserToken | jose.js:29:20:29:28 | UserToken |
| jose.js:27:11:27:47 | UserToken | jose.js:30:26:30:34 | UserToken |
| jose.js:27:11:27:47 | UserToken | jose.js:30:26:30:34 | UserToken |
| jose.js:27:23:27:47 | req.hea ... ization | jose.js:27:11:27:47 | UserToken |
| jose.js:27:23:27:47 | req.hea ... ization | jose.js:27:11:27:47 | UserToken |
#select
| jose.js:14:23:14:47 | req.hea ... ization | jose.js:14:23:14:47 | req.hea ... ization | jose.js:16:20:16:28 | UserToken | Decoding JWT $@. | jose.js:16:20:16:28 | UserToken | without signature verification |

View File

@@ -0,0 +1,35 @@
const express = require('express')
const app = express()
const jwtJsonwebtoken = require('jsonwebtoken');
const jwt_decode = require('jwt-decode');
const jwt_simple = require('jwt-simple');
const jose = require('jose')
const port = 3000
function getSecret() {
return "A Safe generated random key"
}
app.get('/jose1', (req, res) => {
const UserToken = req.headers.authorization;
// BAD: no signature verification
jose.decodeJwt(UserToken)
})
app.get('/jose2', async (req, res) => {
const UserToken = req.headers.authorization;
// GOOD: with signature verification
await jose.jwtVerify(UserToken, new TextEncoder().encode(getSecret()))
})
app.get('/jose3', async (req, res) => {
const UserToken = req.headers.authorization;
// GOOD: first without signature verification then with signature verification for same UserToken
jose.decodeJwt(UserToken)
await jose.jwtVerify(UserToken, new TextEncoder().encode(getSecret()))
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})

View File

@@ -0,0 +1 @@
Security/CWE-347-noVerification/jose.ql

View File

@@ -0,0 +1,13 @@
nodes
| jwtDecode.js:14:11:14:47 | UserToken |
| jwtDecode.js:14:23:14:47 | req.hea ... ization |
| jwtDecode.js:14:23:14:47 | req.hea ... ization |
| jwtDecode.js:18:16:18:24 | UserToken |
| jwtDecode.js:18:16:18:24 | UserToken |
edges
| jwtDecode.js:14:11:14:47 | UserToken | jwtDecode.js:18:16:18:24 | UserToken |
| jwtDecode.js:14:11:14:47 | UserToken | jwtDecode.js:18:16:18:24 | UserToken |
| jwtDecode.js:14:23:14:47 | req.hea ... ization | jwtDecode.js:14:11:14:47 | UserToken |
| jwtDecode.js:14:23:14:47 | req.hea ... ization | jwtDecode.js:14:11:14:47 | UserToken |
#select
| jwtDecode.js:14:23:14:47 | req.hea ... ization | jwtDecode.js:14:23:14:47 | req.hea ... ization | jwtDecode.js:18:16:18:24 | UserToken | Decoding JWT $@. | jwtDecode.js:18:16:18:24 | UserToken | without signature verification |

View File

@@ -0,0 +1,23 @@
const express = require('express')
const app = express()
const jwtJsonwebtoken = require('jsonwebtoken');
const jwt_decode = require('jwt-decode');
const jwt_simple = require('jwt-simple');
const jose = require('jose')
const port = 3000
function getSecret() {
return "A Safe generated random key"
}
app.get('/jwtDecode', (req, res) => {
const UserToken = req.headers.authorization;
// jwt-decode
// BAD: no signature verification
jwt_decode(UserToken)
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})

View File

@@ -0,0 +1 @@
Security/CWE-347-noVerification/jwtDecode.ql

View File

@@ -1,38 +0,0 @@
nodes
| NoVerification.js:63:11:63:47 | UserToken |
| NoVerification.js:63:23:63:47 | req.hea ... ization |
| NoVerification.js:63:23:63:47 | req.hea ... ization |
| NoVerification.js:65:28:65:36 | UserToken |
| NoVerification.js:65:28:65:36 | UserToken |
| NoVerification.js:66:28:66:36 | UserToken |
| NoVerification.js:66:28:66:36 | UserToken |
| NoVerification.js:70:11:70:47 | UserToken |
| NoVerification.js:70:23:70:47 | req.hea ... ization |
| NoVerification.js:70:23:70:47 | req.hea ... ization |
| NoVerification.js:72:28:72:36 | UserToken |
| NoVerification.js:72:28:72:36 | UserToken |
| NoVerification.js:76:11:76:47 | UserToken |
| NoVerification.js:76:23:76:47 | req.hea ... ization |
| NoVerification.js:76:23:76:47 | req.hea ... ization |
| NoVerification.js:78:28:78:36 | UserToken |
| NoVerification.js:78:28:78:36 | UserToken |
| NoVerification.js:79:28:79:36 | UserToken |
| NoVerification.js:79:28:79:36 | UserToken |
edges
| NoVerification.js:63:11:63:47 | UserToken | NoVerification.js:65:28:65:36 | UserToken |
| NoVerification.js:63:11:63:47 | UserToken | NoVerification.js:65:28:65:36 | UserToken |
| NoVerification.js:63:11:63:47 | UserToken | NoVerification.js:66:28:66:36 | UserToken |
| NoVerification.js:63:11:63:47 | UserToken | NoVerification.js:66:28:66:36 | UserToken |
| NoVerification.js:63:23:63:47 | req.hea ... ization | NoVerification.js:63:11:63:47 | UserToken |
| NoVerification.js:63:23:63:47 | req.hea ... ization | NoVerification.js:63:11:63:47 | UserToken |
| NoVerification.js:70:11:70:47 | UserToken | NoVerification.js:72:28:72:36 | UserToken |
| NoVerification.js:70:11:70:47 | UserToken | NoVerification.js:72:28:72:36 | UserToken |
| NoVerification.js:70:23:70:47 | req.hea ... ization | NoVerification.js:70:11:70:47 | UserToken |
| NoVerification.js:70:23:70:47 | req.hea ... ization | NoVerification.js:70:11:70:47 | UserToken |
| NoVerification.js:76:11:76:47 | UserToken | NoVerification.js:78:28:78:36 | UserToken |
| NoVerification.js:76:11:76:47 | UserToken | NoVerification.js:78:28:78:36 | UserToken |
| NoVerification.js:76:11:76:47 | UserToken | NoVerification.js:79:28:79:36 | UserToken |
| NoVerification.js:76:11:76:47 | UserToken | NoVerification.js:79:28:79:36 | UserToken |
| NoVerification.js:76:23:76:47 | req.hea ... ization | NoVerification.js:76:11:76:47 | UserToken |
| NoVerification.js:76:23:76:47 | req.hea ... ization | NoVerification.js:76:11:76:47 | UserToken |
#select

View File

@@ -0,0 +1,39 @@
nodes
| jwtSimple.js:13:11:13:47 | UserToken |
| jwtSimple.js:13:23:13:47 | req.hea ... ization |
| jwtSimple.js:13:23:13:47 | req.hea ... ization |
| jwtSimple.js:18:23:18:31 | UserToken |
| jwtSimple.js:18:23:18:31 | UserToken |
| jwtSimple.js:22:11:22:47 | UserToken |
| jwtSimple.js:22:23:22:47 | req.hea ... ization |
| jwtSimple.js:22:23:22:47 | req.hea ... ization |
| jwtSimple.js:27:23:27:31 | UserToken |
| jwtSimple.js:27:23:27:31 | UserToken |
| jwtSimple.js:28:23:28:31 | UserToken |
| jwtSimple.js:28:23:28:31 | UserToken |
| jwtSimple.js:32:11:32:47 | UserToken |
| jwtSimple.js:32:23:32:47 | req.hea ... ization |
| jwtSimple.js:32:23:32:47 | req.hea ... ization |
| jwtSimple.js:37:23:37:31 | UserToken |
| jwtSimple.js:37:23:37:31 | UserToken |
| jwtSimple.js:38:23:38:31 | UserToken |
| jwtSimple.js:38:23:38:31 | UserToken |
edges
| jwtSimple.js:13:11:13:47 | UserToken | jwtSimple.js:18:23:18:31 | UserToken |
| jwtSimple.js:13:11:13:47 | UserToken | jwtSimple.js:18:23:18:31 | UserToken |
| jwtSimple.js:13:23:13:47 | req.hea ... ization | jwtSimple.js:13:11:13:47 | UserToken |
| jwtSimple.js:13:23:13:47 | req.hea ... ization | jwtSimple.js:13:11:13:47 | UserToken |
| jwtSimple.js:22:11:22:47 | UserToken | jwtSimple.js:27:23:27:31 | UserToken |
| jwtSimple.js:22:11:22:47 | UserToken | jwtSimple.js:27:23:27:31 | UserToken |
| jwtSimple.js:22:11:22:47 | UserToken | jwtSimple.js:28:23:28:31 | UserToken |
| jwtSimple.js:22:11:22:47 | UserToken | jwtSimple.js:28:23:28:31 | UserToken |
| jwtSimple.js:22:23:22:47 | req.hea ... ization | jwtSimple.js:22:11:22:47 | UserToken |
| jwtSimple.js:22:23:22:47 | req.hea ... ization | jwtSimple.js:22:11:22:47 | UserToken |
| jwtSimple.js:32:11:32:47 | UserToken | jwtSimple.js:37:23:37:31 | UserToken |
| jwtSimple.js:32:11:32:47 | UserToken | jwtSimple.js:37:23:37:31 | UserToken |
| jwtSimple.js:32:11:32:47 | UserToken | jwtSimple.js:38:23:38:31 | UserToken |
| jwtSimple.js:32:11:32:47 | UserToken | jwtSimple.js:38:23:38:31 | UserToken |
| jwtSimple.js:32:23:32:47 | req.hea ... ization | jwtSimple.js:32:11:32:47 | UserToken |
| jwtSimple.js:32:23:32:47 | req.hea ... ization | jwtSimple.js:32:11:32:47 | UserToken |
#select
| jwtSimple.js:13:23:13:47 | req.hea ... ization | jwtSimple.js:13:23:13:47 | req.hea ... ization | jwtSimple.js:18:23:18:31 | UserToken | Decoding JWT $@. | jwtSimple.js:18:23:18:31 | UserToken | without signature verification |

View File

@@ -0,0 +1,43 @@
const express = require('express')
const app = express()
const jwtJsonwebtoken = require('jsonwebtoken');
const jwt_decode = require('jwt-decode');
const jwt_simple = require('jwt-simple');
const jose = require('jose')
const port = 3000
function getSecret() {
return "A Safe generated random key"
}
app.get('/jwtSimple1', (req, res) => {
const UserToken = req.headers.authorization;
// jwt-simple
// jwt.decode(token, key, noVerify, algorithm)
// BAD: no signature verification
jwt_simple.decode(UserToken, getSecret(), true);
})
app.get('/jwtSimple2', (req, res) => {
const UserToken = req.headers.authorization;
// jwt-simple
// jwt.decode(token, key, noVerify, algorithm)
// GOOD: with signature verification
jwt_simple.decode(UserToken, getSecret(), false);
jwt_simple.decode(UserToken, getSecret());
})
app.get('/jwtSimple3', (req, res) => {
const UserToken = req.headers.authorization;
// jwt-simple
// jwt.decode(token, key, noVerify, algorithm)
// GOOD: first without signature verification then with signature verification for same UserToken
jwt_simple.decode(UserToken, getSecret(), true);
jwt_simple.decode(UserToken, getSecret());
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})

View File

@@ -0,0 +1 @@
Security/CWE-347-noVerification/jwtSimple.ql