Query upload

This commit is contained in:
jorgectf
2021-04-01 18:31:45 +02:00
parent 20416ae034
commit 5edb3b1153
6 changed files with 183 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
/**
* @name JWT encoding using empty key or algorithm
* @description The application uses an empty secret or algorithm while encoding a JWT Token.
* @kind problem
* @problem.severity warning
* @id py/jwt-empty-secret-or-algorithm
* @tags security
*/
// determine precision above
import python
import experimental.semmle.python.Concepts
import experimental.semmle.python.security.JWT
from JWTEncoding jwtEncoding, string affectedComponent
where
exists( |
affectedComponent = "algorithm" and
isEmptyOrNone(jwtEncoding.getAlgorithmNode())
or
affectedComponent = "key" and
isEmptyOrNone(jwtEncoding.getKeyNode())
)
select jwtEncoding, affectedComponent, "is empty."

View File

@@ -0,0 +1,17 @@
/**
* @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
* @problem.severity warning
* @id py/jwt-missing-verification
* @tags security
* external/cwe/cwe-347
*/
// determine precision above
import python
import experimental.semmle.python.Concepts
from JWTDecoding jwtDecoding
where not jwtDecoding.verifiesSignature()
select jwtDecoding, "does not verify the JWT payload with a cryptographic secret or public key."

View File

@@ -0,0 +1,23 @@
import jwt
# Encoding
# good - key and algorithm
jwt.encode({"foo": "bar"}, "key", "HS256")
jwt.encode({"foo": "bar"}, key="key", algorithm="HS256")
# bad - both key and algorithm set to None
jwt.encode({"foo": "bar"}, None, None)
# bad - empty key
jwt.encode({"foo": "bar"}, "", algorithm="HS256")
jwt.encode({"foo": "bar"}, key="", algorithm="HS256")
# Decoding
# good
jwt.decode(token, "key", "HS256")
# bad - unverified decoding
jwt.decode(token, verify=False)
jwt.decode(token, key, options={"verify_signature": False})

View File

@@ -13,3 +13,77 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.TaintTracking
private import experimental.semmle.python.Frameworks
/** Provides classes for modeling JWT-related APIs. */
module JWTEncoding {
/**
* A data-flow node that collects methods encoding 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 key.
*/
abstract DataFlow::Node getKeyNode();
/**
* Gets the algorithm Node used in the encoding.
*/
abstract DataFlow::Node getAlgorithmNode();
/**
* Tries to get the algorithm used in the encoding.
*/
abstract string getAlgorithm();
}
}
/**
* A data-flow node that collect methods immediately executing an expression.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `JWTEncoding::Range` instead.
*/
class JWTEncoding extends DataFlow::Node {
JWTEncoding::Range range;
JWTEncoding() { this = range }
DataFlow::Node getKeyNode() { result = range.getKeyNode() }
DataFlow::Node getAlgorithmNode() { result = range.getAlgorithmNode() }
string getAlgorithm() { result = range.getAlgorithm() }
}
/** Provides classes for modeling Regular Expression escape-related APIs. */
module JWTDecoding {
/**
* A data-flow node that collects functions escaping regular expressions.
*
* 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 escaped expression.
*/
abstract predicate verifiesSignature();
}
}
/**
* A data-flow node that collects functions escaping regular expressions.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `JWTDecoding::Range` instead.
*/
class JWTDecoding extends DataFlow::Node {
JWTDecoding::Range range;
JWTDecoding() { this = range }
predicate verifiesSignature() { range.verifiesSignature() }
}

View File

@@ -9,3 +9,37 @@ private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.dataflow.new.RemoteFlowSources
private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
private module JWT {
private class PyJWTEncodeCall extends DataFlow::CallCfgNode, JWTEncoding::Range {
PyJWTEncodeCall() { this = API::moduleImport("jwt").getMember("encode").getACall() }
override DataFlow::Node getKeyNode() {
result = this.getArg(1) or result = this.getArgByName("key")
}
override DataFlow::Node getAlgorithmNode() {
result = this.getArg(2) or
result = this.getArgByName("algorithm")
}
override string getAlgorithm() { result = getAlgorithmNode().asExpr().(Str_).getS() }
}
private class PyJWTDecodeCall extends DataFlow::CallCfgNode, JWTDecoding::Range {
PyJWTDecodeCall() { this = API::moduleImport("jwt").getMember("decode").getACall() }
override predicate verifiesSignature() {
not exists(NameConstant falseName |
falseName.getId() = "False" and
exists( | falseName = this.getArgByName("verify").asExpr())
or
exists(KeyValuePair optionsDict |
optionsDict = this.getArgByName("options").asExpr().(Dict).getItems().getAnItem() and
optionsDict.getKey().(Str_).getS().matches("verify_signature") and
falseName = optionsDict.getValue()
)
)
}
}
}

View File

@@ -0,0 +1,11 @@
import python
import experimental.semmle.python.Concepts
import semmle.python.dataflow.new.DataFlow
predicate isEmptyOrNone(DataFlow::Node arg) { isEmpty(arg) or isNone(arg) }
predicate isEmpty(DataFlow::Node arg) { arg.asExpr().(Str_).getS() = "" }
predicate isNone(DataFlow::Node arg) {
exists(NameConstant noneName | noneName.getId() = "None" and arg.asExpr() = noneName)
}