mirror of
https://github.com/github/codeql.git
synced 2026-05-02 12:15:17 +02:00
Polish documentation
This commit is contained in:
@@ -4,11 +4,11 @@
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Applications encoding a JSON Web Token (JWT) may be vulnerable when the applied key or algorithm
|
||||
is empty or None.</p>
|
||||
is empty or <code>None</code>.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Use non-empty nor None values while encoding JWT payloads.</p>
|
||||
<p>Use non-empty nor <code>None</code> values while encoding JWT payloads.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
private import python
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
/** Checks if the argument is empty or none. */
|
||||
predicate isEmptyOrNone(DataFlow::Node arg) { isEmpty(arg) or isNone(arg) }
|
||||
|
||||
/** Checks if an empty string `""` flows to `arg` */
|
||||
predicate isEmpty(DataFlow::Node arg) {
|
||||
exists(StrConst emptyString |
|
||||
emptyString.getText() = "" and
|
||||
@@ -10,11 +12,12 @@ predicate isEmpty(DataFlow::Node arg) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Checks if `None` flows to `arg` */
|
||||
predicate isNone(DataFlow::Node arg) {
|
||||
exists( | DataFlow::exprNode(any(None no)).(DataFlow::LocalSourceNode).flowsTo(arg))
|
||||
}
|
||||
|
||||
/** Checks if `False` flows to `arg` */
|
||||
predicate isFalse(DataFlow::Node arg) {
|
||||
exists( | DataFlow::exprNode(any(False falseExpr)).(DataFlow::LocalSourceNode).flowsTo(arg))
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,23 @@ private module Authlib {
|
||||
/** Gets a reference to `jwt.decode` */
|
||||
private API::Node authlibJWTDecode() { result = authlibJWT().getMember("decode") }
|
||||
|
||||
// def encode(self, header, payload, key, check=True):
|
||||
/**
|
||||
* Gets a call to `authlib.jose.(jwt|JsonWebToken).encode`.
|
||||
*
|
||||
* Given the following example:
|
||||
*
|
||||
* ```py
|
||||
* jwt.encode({"alg": "HS256"}, token, "key")
|
||||
* ```
|
||||
*
|
||||
* * `this` would be `jwt.encode({"alg": "HS256"}, token, "key")`.
|
||||
* * `getPayload()`'s result would be `token`.
|
||||
* * `getKey()`'s result would be `"key"`.
|
||||
* * `getAlgorithm()`'s result would be `"HS256"`.
|
||||
* * `getAlgorithmstring()`'s result would be `HS256`.
|
||||
*/
|
||||
private class AuthlibJWTEncodeCall extends DataFlow::CallCfgNode, JWTEncoding::Range {
|
||||
// def encode(self, header, payload, key, check=True):
|
||||
AuthlibJWTEncodeCall() { this = authlibJWTEncode().getACall() }
|
||||
|
||||
override DataFlow::Node getPayload() { result = this.getArg(1) }
|
||||
@@ -42,8 +57,21 @@ private module Authlib {
|
||||
}
|
||||
}
|
||||
|
||||
// def decode(self, s, key, claims_cls=None, claims_options=None, claims_params=None):
|
||||
/**
|
||||
* Gets a call to `authlib.jose.(jwt|JsonWebToken).decode`
|
||||
*
|
||||
* Given the following example:
|
||||
*
|
||||
* ```py
|
||||
* jwt.decode(token, key)
|
||||
* ```
|
||||
*
|
||||
* * `this` would be `jwt.decode(token, key)`.
|
||||
* * `getPayload()`'s result would be `token`.
|
||||
* * `getKey()`'s result would be `key`.
|
||||
*/
|
||||
private class AuthlibJWTDecodeCall extends DataFlow::CallCfgNode, JWTDecoding::Range {
|
||||
// def decode(self, s, key, claims_cls=None, claims_options=None, claims_params=None):
|
||||
AuthlibJWTDecodeCall() { this = authlibJWTDecode().getACall() }
|
||||
|
||||
override DataFlow::Node getPayload() { result = this.getArg(0) }
|
||||
|
||||
@@ -10,8 +10,23 @@ private module PyJWT {
|
||||
/** Gets a reference to `jwt.decode` */
|
||||
private API::Node pyjwtDecode() { result = API::moduleImport("jwt").getMember("decode") }
|
||||
|
||||
// def encode(self, payload, key, algorithm="HS256", headers=None, json_encoder=None)
|
||||
/**
|
||||
* Gets a call to `jwt.encode`.
|
||||
*
|
||||
* Given the following example:
|
||||
*
|
||||
* ```py
|
||||
* jwt.encode(token, "key", "HS256")
|
||||
* ```
|
||||
*
|
||||
* * `this` would be `jwt.encode(token, "key", "HS256")`.
|
||||
* * `getPayload()`'s result would be `token`.
|
||||
* * `getKey()`'s result would be `"key"`.
|
||||
* * `getAlgorithm()`'s result would be `"HS256"`.
|
||||
* * `getAlgorithmstring()`'s result would be `HS256`.
|
||||
*/
|
||||
private class PyJWTEncodeCall extends DataFlow::CallCfgNode, JWTEncoding::Range {
|
||||
// def encode(self, payload, key, algorithm="HS256", headers=None, json_encoder=None)
|
||||
PyJWTEncodeCall() { this = pyjwtEncode().getACall() }
|
||||
|
||||
override DataFlow::Node getPayload() {
|
||||
@@ -32,8 +47,25 @@ private module PyJWT {
|
||||
}
|
||||
}
|
||||
|
||||
// def decode(self, jwt, key="", algorithms=None, options=None)
|
||||
/**
|
||||
* Gets a call to `jwt.decode`.
|
||||
*
|
||||
* Given the following example:
|
||||
*
|
||||
* ```py
|
||||
* jwt.decode(token, key, "HS256", options={"verify_signature": True})
|
||||
* ```
|
||||
*
|
||||
* * `this` would be `jwt.decode(token, key, options={"verify_signature": True})`.
|
||||
* * `getPayload()`'s result would be `token`.
|
||||
* * `getKey()`'s result would be `key`.
|
||||
* * `getAlgorithm()`'s result would be `"HS256"`.
|
||||
* * `getAlgorithmstring()`'s result would be `HS256`.
|
||||
* * `getOptions()`'s result would be `{"verify_signature": True}`.
|
||||
* * `verifiesSignature()` predicate would succeed.
|
||||
*/
|
||||
private class PyJWTDecodeCall extends DataFlow::CallCfgNode, JWTDecoding::Range {
|
||||
// def decode(self, jwt, key="", algorithms=None, options=None)
|
||||
PyJWTDecodeCall() { this = pyjwtDecode().getACall() }
|
||||
|
||||
override DataFlow::Node getPayload() { result in [this.getArg(0), this.getArgByName("jwt")] }
|
||||
|
||||
@@ -13,8 +13,23 @@ private module PythonJose {
|
||||
/** Gets a reference to `jwt.decode` */
|
||||
private API::Node joseJWTDecode() { result = joseJWT().getMember("decode") }
|
||||
|
||||
// def encode(claims, key, algorithm=ALGORITHMS.HS256, headers=None, access_token=None):
|
||||
/**
|
||||
* Gets a call to `jwt.encode`.
|
||||
*
|
||||
* Given the following example:
|
||||
*
|
||||
* ```py
|
||||
* jwt.encode(token, key="key", algorithm="HS256")
|
||||
* ```
|
||||
*
|
||||
* * `this` would be `jwt.encode(token, key="key", algorithm="HS256")`.
|
||||
* * `getPayload()`'s result would be `token`.
|
||||
* * `getKey()`'s result would be `"key"`.
|
||||
* * `getAlgorithm()`'s result would be `"HS256"`.
|
||||
* * `getAlgorithmstring()`'s result would be `HS256`.
|
||||
*/
|
||||
private class JoseJWTEncodeCall extends DataFlow::CallCfgNode, JWTEncoding::Range {
|
||||
// def encode(claims, key, algorithm=ALGORITHMS.HS256, headers=None, access_token=None):
|
||||
JoseJWTEncodeCall() { this = joseJWTEncode().getACall() }
|
||||
|
||||
override DataFlow::Node getPayload() { result = this.getArg(0) }
|
||||
@@ -33,8 +48,25 @@ private module PythonJose {
|
||||
}
|
||||
}
|
||||
|
||||
// def decode(token, key, algorithms=None, options=None, audience=None, issuer=None, subject=None, access_token=None):
|
||||
/**
|
||||
* Gets a call to `jwt.decode`.
|
||||
*
|
||||
* Given the following example:
|
||||
*
|
||||
* ```py
|
||||
* jwt.decode(token, "key", "HS256")
|
||||
* ```
|
||||
*
|
||||
* * `this` would be `jwt.decode(token, "key", "HS256")`.
|
||||
* * `getPayload()`'s result would be `token`.
|
||||
* * `getKey()`'s result would be `"key"`.
|
||||
* * `getAlgorithm()`'s result would be `"HS256"`.
|
||||
* * `getAlgorithmstring()`'s result would be `HS256`.
|
||||
* * `getOptions()`'s result would be none.
|
||||
* * `verifiesSignature()` predicate would succeed.
|
||||
*/
|
||||
private class JoseJWTDecodeCall extends DataFlow::CallCfgNode, JWTDecoding::Range {
|
||||
// def decode(token, key, algorithms=None, options=None, audience=None, issuer=None, subject=None, access_token=None):
|
||||
JoseJWTDecodeCall() { this = joseJWTDecode().getACall() }
|
||||
|
||||
override DataFlow::Node getPayload() { result = this.getArg(0) }
|
||||
|
||||
Reference in New Issue
Block a user