add same query but with local source support to comply with the CVE-2021-37580

This commit is contained in:
am0o0
2024-07-31 10:58:04 +02:00
parent 96c142bf0a
commit 701e3d7e53
3 changed files with 136 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
/**
* @name Missing JWT signature check
* @description Failing to check the Json Web Token (JWT) signature may allow an attacker to forge their own tokens.
* @kind path-problem
* @problem.severity error
* @security-severity 7.8
* @precision medium
* @id java/missing-jwt-signature-check-auth0-local-source
* @tags security
* external/cwe/cwe-347
*/
import java
import semmle.code.java.dataflow.FlowSources
module JwtAuth0 {
class PayloadType extends RefType {
PayloadType() { this.hasQualifiedName("com.auth0.jwt.interfaces", "Payload") }
}
class JwtType extends RefType {
JwtType() { this.hasQualifiedName("com.auth0.jwt", "JWT") }
}
class JwtVerifierType extends RefType {
JwtVerifierType() { this.hasQualifiedName("com.auth0.jwt", "JWTVerifier") }
}
/**
* A Method that returns a Decoded Claim of JWT
*/
class GetPayload extends MethodCall {
GetPayload() {
this.getCallee().getDeclaringType() instanceof PayloadType and
this.getCallee().hasName(["getClaim", "getIssuedAt"])
}
}
/**
* A Method that Decode JWT without signature verification
*/
class Decode extends MethodCall {
Decode() {
this.getCallee().getDeclaringType() instanceof JwtType and
this.getCallee().hasName("decode")
}
}
/**
* A Method that Decode JWT with signature verification
*/
class Verify extends MethodCall {
Verify() {
this.getCallee().getDeclaringType() instanceof JwtVerifierType and
this.getCallee().hasName("verify")
}
}
}
module JwtDecodeConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(Variable v |
source.asExpr() = v.getInitializer() and
v.getType().hasName("String")
) and
not FlowToJwtVerify::flow(source, _)
}
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(JwtAuth0::GetPayload a) }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// Decode Should be one of the middle nodes
exists(JwtAuth0::Decode a |
nodeFrom.asExpr() = a.getArgument(0) and
nodeTo.asExpr() = a
)
or
exists(JwtAuth0::Verify a |
nodeFrom.asExpr() = a.getArgument(0) and
nodeTo.asExpr() = a
)
or
exists(JwtAuth0::GetPayload a |
nodeFrom.asExpr() = a.getQualifier() and
nodeTo.asExpr() = a
)
}
}
module FlowToJwtVerifyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(Variable v |
source.asExpr() = v.getInitializer() and
v.getType().hasName("String")
)
}
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(JwtAuth0::Verify a).getArgument(0) }
}
module JwtDecode = TaintTracking::Global<JwtDecodeConfig>;
module FlowToJwtVerify = TaintTracking::Global<FlowToJwtVerifyConfig>;
import JwtDecode::PathGraph
from JwtDecode::PathNode source, JwtDecode::PathNode sink
where JwtDecode::flowPath(source, sink)
select sink.getNode(), source, sink, "This parses a $@, but the signature is not verified.",
source.getNode(), "JWT"

View File

@@ -0,0 +1,24 @@
edges
| JwtNoVerifier.java:42:28:42:55 | getParameter(...) : String | JwtNoVerifier.java:43:39:43:47 | JwtToken2 : String | provenance | Src:MaD:44684 |
| JwtNoVerifier.java:43:39:43:47 | JwtToken2 : String | JwtNoVerifier.java:72:38:72:55 | token : String | provenance | |
| JwtNoVerifier.java:72:38:72:55 | token : String | JwtNoVerifier.java:73:37:73:41 | token : String | provenance | |
| JwtNoVerifier.java:73:26:73:42 | decode(...) : DecodedJWT | JwtNoVerifier.java:74:28:74:30 | jwt : DecodedJWT | provenance | |
| JwtNoVerifier.java:73:37:73:41 | token : String | JwtNoVerifier.java:73:26:73:42 | decode(...) : DecodedJWT | provenance | Config |
| JwtNoVerifier.java:74:16:74:31 | of(...) : Optional [<element>] : DecodedJWT | JwtNoVerifier.java:74:37:74:40 | item : DecodedJWT | provenance | MaD:43977 |
| JwtNoVerifier.java:74:28:74:30 | jwt : DecodedJWT | JwtNoVerifier.java:74:16:74:31 | of(...) : Optional [<element>] : DecodedJWT | provenance | MaD:43979 |
| JwtNoVerifier.java:74:37:74:40 | item : DecodedJWT | JwtNoVerifier.java:74:45:74:48 | item : DecodedJWT | provenance | |
| JwtNoVerifier.java:74:45:74:48 | item : DecodedJWT | JwtNoVerifier.java:74:45:74:69 | getClaim(...) | provenance | Config |
nodes
| JwtNoVerifier.java:42:28:42:55 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| JwtNoVerifier.java:43:39:43:47 | JwtToken2 : String | semmle.label | JwtToken2 : String |
| JwtNoVerifier.java:72:38:72:55 | token : String | semmle.label | token : String |
| JwtNoVerifier.java:73:26:73:42 | decode(...) : DecodedJWT | semmle.label | decode(...) : DecodedJWT |
| JwtNoVerifier.java:73:37:73:41 | token : String | semmle.label | token : String |
| JwtNoVerifier.java:74:16:74:31 | of(...) : Optional [<element>] : DecodedJWT | semmle.label | of(...) : Optional [<element>] : DecodedJWT |
| JwtNoVerifier.java:74:28:74:30 | jwt : DecodedJWT | semmle.label | jwt : DecodedJWT |
| JwtNoVerifier.java:74:37:74:40 | item : DecodedJWT | semmle.label | item : DecodedJWT |
| JwtNoVerifier.java:74:45:74:48 | item : DecodedJWT | semmle.label | item : DecodedJWT |
| JwtNoVerifier.java:74:45:74:69 | getClaim(...) | semmle.label | getClaim(...) |
subpaths
#select
| JwtNoVerifier.java:74:45:74:69 | getClaim(...) | JwtNoVerifier.java:42:28:42:55 | getParameter(...) : String | JwtNoVerifier.java:74:45:74:69 | getClaim(...) | This parses a $@, but the signature is not verified. | JwtNoVerifier.java:42:28:42:55 | getParameter(...) | JWT |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-347/Auth0NoVerifierLocalSource.ql