-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Java: Promote Missing JWT signature check query from experimental #5911
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
atorralba
merged 21 commits into
github:main
from
atorralba:atorralba/promote-missing-jwt-signature-check
Aug 5, 2021
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
3e4ccaf
Move from experimental to standard
atorralba 897cd53
Created JWT.qll and refactored to use CSV models
atorralba cfb38c4
QLDocs
atorralba bc2370a
Use InlineExpectationsTest for tests
atorralba 347bd2e
Added change note
atorralba 34a55e7
Add missing subtype test
atorralba 91ba30a
Merge branch 'main' into atorralba/promote-missing-jwt-signature-check
atorralba 2dd8626
Generic type parameters no longer needed in CSV sink models
atorralba 430d9f1
Merge branch 'main' into atorralba/promote-missing-jwt-signature-check
atorralba 22c9baa
Refactor JWT.qll
atorralba ed0db7c
Fix release note
atorralba 76905c4
Formatting
atorralba ebf004a
Update MissingJWTSignatureCheck.qhelp
mchammer01 4ea6729
Update java/ql/src/Security/CWE/CWE-347/MissingJWTSignatureCheck.ql
atorralba f4bc4df
Renamed JWTQuery so that it's named after the actual query name
atorralba b586f3e
Make the additional flow step abstract
atorralba 452fd9a
Refactor to path query
atorralba a046d75
Apply suggestions from code review
atorralba bc9563c
Apply suggestions from code review
atorralba 78998d0
Update java/ql/src/semmle/code/java/security/JWT.qll
aschackmull 5f9f857
Update java/ql/src/semmle/code/java/security/JWT.qll
aschackmull File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
2 changes: 2 additions & 0 deletions
2
java/change-notes/2021-05-17-missing-jwt-signature-check-query.md
This file contains hidden or 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 file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| lgtm,codescanning | ||
| * The query "Missing JWT signature check" (`java/missing-jwt-signature-check`) has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @intrigus-lgtm](https://github.com/github/codeql/pull/5597). |
File renamed without changes.
This file contains hidden or 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
20 changes: 20 additions & 0 deletions
20
java/ql/src/Security/CWE/CWE-347/MissingJWTSignatureCheck.ql
This file contains hidden or 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 file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| /** | ||
| * @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 high | ||
| * @id java/missing-jwt-signature-check | ||
| * @tags security | ||
| * external/cwe/cwe-347 | ||
| */ | ||
|
|
||
| import java | ||
| import semmle.code.java.security.MissingJWTSignatureCheckQuery | ||
| import DataFlow::PathGraph | ||
|
|
||
| from DataFlow::PathNode source, DataFlow::PathNode sink, MissingJwtSignatureCheckConf conf | ||
| where conf.hasFlowPath(source, sink) | ||
| select sink.getNode(), source, sink, "A signing key is set $@, but the signature is not verified.", | ||
| source.getNode(), "here" |
200 changes: 0 additions & 200 deletions
200
java/ql/src/experimental/Security/CWE/CWE-347/MissingJWTSignatureCheck.ql
This file was deleted.
Oops, something went wrong.
This file contains hidden or 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 file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| /** Provides classes for working with JSON Web Token (JWT) libraries. */ | ||
|
|
||
| import java | ||
| private import semmle.code.java.dataflow.DataFlow | ||
|
|
||
| /** A method access that assigns signing keys to a JWT parser. */ | ||
| class JwtParserWithInsecureParseSource extends DataFlow::Node { | ||
| JwtParserWithInsecureParseSource() { | ||
| exists(MethodAccess ma, Method m | | ||
| m.getDeclaringType().getASupertype*() instanceof TypeJwtParser or | ||
| m.getDeclaringType().getASupertype*() instanceof TypeJwtParserBuilder | ||
| | | ||
| this.asExpr() = ma and | ||
| ma.getMethod() = m and | ||
| m.hasName(["setSigningKey", "setSigningKeyResolver"]) | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * The qualifier of an insecure parsing method. | ||
| * That is, either the qualifier of a call to the `parse(token)`, | ||
| * `parseClaimsJwt(token)` or `parsePlaintextJwt(token)` methods or | ||
| * the qualifier of a call to a `parse(token, handler)` method | ||
| * where the `handler` is considered insecure. | ||
| */ | ||
| class JwtParserWithInsecureParseSink extends DataFlow::Node { | ||
| MethodAccess insecureParseMa; | ||
|
|
||
| JwtParserWithInsecureParseSink() { | ||
| insecureParseMa.getQualifier() = this.asExpr() and | ||
| exists(Method m | | ||
| insecureParseMa.getMethod() = m and | ||
| m.getDeclaringType().getASupertype*() instanceof TypeJwtParser and | ||
| m.hasName(["parse", "parseClaimsJwt", "parsePlaintextJwt"]) and | ||
aschackmull marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ( | ||
| m.getNumberOfParameters() = 1 | ||
| or | ||
| isInsecureJwtHandler(insecureParseMa.getArgument(1)) | ||
| ) | ||
| ) | ||
| } | ||
|
|
||
| /** Gets the method access that does the insecure parsing. */ | ||
| MethodAccess getParseMethodAccess() { result = insecureParseMa } | ||
| } | ||
|
|
||
| /** | ||
| * A unit class for adding additional flow steps. | ||
| * | ||
| * Extend this class to add additional flow steps that should apply to the `MissingJwtSignatureCheckConf`. | ||
| */ | ||
| class JwtParserWithInsecureParseAdditionalFlowStep extends Unit { | ||
| abstract predicate step(DataFlow::Node node1, DataFlow::Node node2); | ||
| } | ||
|
|
||
| /** A set of additional flow steps to consider when working with JWT parsing related data flows. */ | ||
| private class DefaultJwtParserWithInsecureParseAdditionalFlowStep extends JwtParserWithInsecureParseAdditionalFlowStep { | ||
| override predicate step(DataFlow::Node node1, DataFlow::Node node2) { | ||
| jwtParserStep(node1.asExpr(), node2.asExpr()) | ||
| } | ||
| } | ||
|
|
||
| /** Models the builder style of `JwtParser` and `JwtParserBuilder`. */ | ||
| private predicate jwtParserStep(Expr parser, MethodAccess ma) { | ||
| ( | ||
| parser.getType().(RefType).getASourceSupertype*() instanceof TypeJwtParser or | ||
| parser.getType().(RefType).getASourceSupertype*() instanceof TypeJwtParserBuilder | ||
| ) and | ||
| ma.getQualifier() = parser | ||
| } | ||
|
|
||
| /** | ||
| * Holds if `parseHandlerExpr` is an insecure `JwtHandler`. | ||
| * That is, it overrides a method from `JwtHandlerOnJwtMethod` and | ||
| * the override is not defined on `JwtHandlerAdapter`. | ||
| * `JwtHandlerAdapter`'s overrides are safe since they always throw an exception. | ||
| */ | ||
| private predicate isInsecureJwtHandler(Expr parseHandlerExpr) { | ||
| exists(RefType t | | ||
| parseHandlerExpr.getType() = t and | ||
| t.getASourceSupertype*() instanceof TypeJwtHandler and | ||
| exists(Method m | | ||
| m = t.getAMethod() and | ||
| m.getASourceOverriddenMethod+() instanceof JwtHandlerOnJwtMethod and | ||
| not m.getSourceDeclaration() instanceof JwtHandlerAdapterOnJwtMethod | ||
| ) | ||
| ) | ||
| } | ||
|
|
||
| /** The interface `io.jsonwebtoken.JwtParser`. */ | ||
| private class TypeJwtParser extends Interface { | ||
| TypeJwtParser() { this.hasQualifiedName("io.jsonwebtoken", "JwtParser") } | ||
| } | ||
|
|
||
| /** The interface `io.jsonwebtoken.JwtParserBuilder`. */ | ||
| private class TypeJwtParserBuilder extends Interface { | ||
| TypeJwtParserBuilder() { this.hasQualifiedName("io.jsonwebtoken", "JwtParserBuilder") } | ||
| } | ||
|
|
||
| /** The interface `io.jsonwebtoken.JwtHandler`. */ | ||
| private class TypeJwtHandler extends Interface { | ||
| TypeJwtHandler() { this.hasQualifiedName("io.jsonwebtoken", "JwtHandler") } | ||
| } | ||
|
|
||
| /** The class `io.jsonwebtoken.JwtHandlerAdapter`. */ | ||
| private class TypeJwtHandlerAdapter extends Class { | ||
| TypeJwtHandlerAdapter() { this.hasQualifiedName("io.jsonwebtoken", "JwtHandlerAdapter") } | ||
| } | ||
|
|
||
| /** The `on(Claims|Plaintext)Jwt` methods defined in `JwtHandler`. */ | ||
| private class JwtHandlerOnJwtMethod extends Method { | ||
| JwtHandlerOnJwtMethod() { | ||
| this.hasName(["onClaimsJwt", "onPlaintextJwt"]) and | ||
| this.getNumberOfParameters() = 1 and | ||
| this.getDeclaringType() instanceof TypeJwtHandler | ||
| } | ||
| } | ||
|
|
||
| /** The `on(Claims|Plaintext)Jwt` methods defined in `JwtHandlerAdapter`. */ | ||
| private class JwtHandlerAdapterOnJwtMethod extends Method { | ||
| JwtHandlerAdapterOnJwtMethod() { | ||
| this.hasName(["onClaimsJwt", "onPlaintextJwt"]) and | ||
| this.getNumberOfParameters() = 1 and | ||
| this.getDeclaringType() instanceof TypeJwtHandlerAdapter | ||
| } | ||
| } | ||
23 changes: 23 additions & 0 deletions
23
java/ql/src/semmle/code/java/security/MissingJWTSignatureCheckQuery.qll
This file contains hidden or 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 file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| /** Provides classes to be used in queries related to JSON Web Token (JWT) signature vulnerabilities. */ | ||
|
|
||
| import java | ||
| import semmle.code.java.dataflow.DataFlow | ||
| import semmle.code.java.security.JWT | ||
|
|
||
| /** | ||
| * Models flow from signing keys assignments to qualifiers of JWT insecure parsers. | ||
| * This is used to determine whether a `JwtParser` performing unsafe parsing has a signing key set. | ||
| */ | ||
| class MissingJwtSignatureCheckConf extends DataFlow::Configuration { | ||
| MissingJwtSignatureCheckConf() { this = "SigningToExprDataFlow" } | ||
|
|
||
| override predicate isSource(DataFlow::Node source) { | ||
| source instanceof JwtParserWithInsecureParseSource | ||
| } | ||
|
|
||
| override predicate isSink(DataFlow::Node sink) { sink instanceof JwtParserWithInsecureParseSink } | ||
|
|
||
| override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { | ||
| any(JwtParserWithInsecureParseAdditionalFlowStep c).step(node1, node2) | ||
| } | ||
| } |
8 changes: 0 additions & 8 deletions
8
java/ql/test/experimental/query-tests/security/CWE-347/MissingJWTSignatureCheck.expected
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.