Add JWT Security Queries

This commit is contained in:
Maiky
2023-08-25 21:28:53 +02:00
parent cf53956d39
commit 17565cde75
17 changed files with 312 additions and 0 deletions

View File

@@ -1250,3 +1250,92 @@ module LdapExecution {
abstract DataFlow::Node getQuery();
}
}
/**
* A data-flow node that encodes a Jwt token.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `JwtEncoding::Range` instead.
*/
class JwtEncoding extends DataFlow::Node instanceof JwtEncoding::Range {
/** Gets the argument containing the encoding payload. */
DataFlow::Node getPayload() { result = super.getPayload() }
/** Gets the argument containing the encoding algorithm. */
DataFlow::Node getAlgorithm() { result = super.getAlgorithm() }
/** Gets the argument containing the encoding key. */
DataFlow::Node getKey() { result = super.getKey() }
/** Checks if the payloads gets signed while encoding. */
predicate signs() { super.signs() }
}
/** Provides a class for modeling new Jwt token encoding APIs. */
module JwtEncoding {
/**
* A data-flow node that encodes a Jwt token.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `JwtEncoding` instead.
*/
abstract class Range extends DataFlow::Node {
/** Gets the argument containing the encoding payload. */
abstract DataFlow::Node getPayload();
/** Gets the argument containing the encoding algorithm. */
abstract DataFlow::Node getAlgorithm();
/** Gets the argument containing the encoding key. */
abstract DataFlow::Node getKey();
/** Checks if the payloads gets signed while encoding. */
abstract predicate signs();
}
}
/**
* A data-flow node that decodes a Jwt token.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `JwtDecoding::Range` instead.
*/
class JwtDecoding extends DataFlow::Node instanceof JwtDecoding::Range {
/** Gets the argument containing the encoding payload. */
DataFlow::Node getPayload() { result = super.getPayload() }
/** Gets the argument containing the encoding algorithm. */
DataFlow::Node getAlgorithm() { result = super.getAlgorithm() }
/** Gets the argument containing the encoding key. */
DataFlow::Node getOptions() { result = super.getOptions() }
/** Checks if the signature gets verified while decoding. */
predicate verifies() { super.verifies() }
}
/** Provides a class for modeling new Jwt token encoding APIs. */
module JwtDecoding {
/**
* A data-flow node that encodes a Jwt token.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `JwtDecoding` instead.
*/
abstract class Range extends DataFlow::Node {
/** Gets the argument containing the encoding payload. */
abstract DataFlow::Node getPayload();
/** Gets the argument containing the encoding algorithm. */
abstract DataFlow::Node getAlgorithm();
/** Gets the argument containing the encoding key. */
abstract DataFlow::Node getKey();
/** Gets the argument containing the encoding options. */
abstract DataFlow::Node getOptions();
/** Checks if the signature gets verified while decoding. */
abstract predicate verifies();
}
}

View File

@@ -37,3 +37,4 @@ private import codeql.ruby.frameworks.Pg
private import codeql.ruby.frameworks.Yaml
private import codeql.ruby.frameworks.Sequel
private import codeql.ruby.frameworks.Ldap
private import codeql.ruby.frameworks.Jwt

View File

@@ -0,0 +1,55 @@
/**
* Provides creation, verification and decoding JSON Web Tokens (JWT).
*/
private import ruby
private import codeql.ruby.ApiGraphs
private import codeql.ruby.dataflow.FlowSummary
private import codeql.ruby.Concepts
/**
* Provides creation, verification and decoding JSON Web Tokens (JWT).
*/
module Jwt {
/** A call to `JWT.encode`, considered as a JWT encoding. */
private class JwtEncode extends JwtEncoding::Range, DataFlow::CallNode {
JwtEncode() { this = API::getTopLevelMember("JWT").getAMethodCall("encode") }
override DataFlow::Node getPayload() { result = this.getArgument(0) }
override DataFlow::Node getAlgorithm() { result = this.getArgument(2) }
override DataFlow::Node getKey() { result = this.getArgument(1) }
override predicate signs() {
not (this.getKey().getConstantValue().isStringlikeValue("") or this.getKey().(DataFlow::ExprNode).getConstantValue().isNil())
}
}
/** A call to `JWT.decode`, considered as a JWT decoding. */
private class JwtDecode extends JwtDecoding::Range, DataFlow::CallNode {
JwtDecode() { this = API::getTopLevelMember("JWT").getAMethodCall("decode") }
override DataFlow::Node getPayload() { result = this.getArgument(0) }
override DataFlow::Node getAlgorithm() {
result.asExpr().getExpr() = this.getArgument(3).asExpr().getExpr().(Pair).getValue() or
result =
this.getArgument(3)
.(DataFlow::HashLiteralNode)
.getElementFromKey(any(Ast::ConstantValue cv | cv.isStringlikeValue("algorithm"))) or
result = this.getArgument(2)
}
override DataFlow::Node getKey() { result = this.getArgument(1) }
override DataFlow::Node getOptions() { result = this.getArgument(3) }
override predicate verifies() {
not this.getArgument(2).getConstantValue().isBoolean(false) and
not this.getAlgorithm().getConstantValue().isStringlikeValue("none")
or
this.getNumberOfArguments() < 3
}
}
}