fix issues according to codereview

This commit is contained in:
amammad
2023-10-10 23:12:30 +02:00
parent 2579791f51
commit 38b0ed8176
7 changed files with 67 additions and 19 deletions

View File

@@ -3,13 +3,15 @@ package main
import (
"fmt"
"log"
"github.com/go-jose/go-jose/v3/jwt"
)
var JwtKey = []byte("AllYourBase")
func main() {
// BAD: usage of a harcoded Key
verifyJWT(token)
verifyJWT(JWTFromUser)
}
func LoadJwtKey(token *jwt.Token) (interface{}, error) {

View File

@@ -12,7 +12,7 @@
import go
import experimental.frameworks.JWT
module JwtPaseWithConstantKeyConfig implements DataFlow::ConfigSig {
module JwtParseWithConstantKeyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof StringLit }
predicate isSink(DataFlow::Node sink) {
@@ -20,18 +20,19 @@ module JwtPaseWithConstantKeyConfig implements DataFlow::ConfigSig {
// Find a node that has flow to a key Function argument
// then find the first result node of this Function which is the secret key
exists(FuncDef fd, DataFlow::Node n, DataFlow::ResultNode rn |
GolangJwtKeyFunc::flow(n, _) and fd = n.asExpr()
|
GolangJwtKeyFunc::flow(n, _) and
sink = rn and
fd = n.asExpr() and
rn.getRoot() = fd and
rn.getIndex() = 0 and
sink = rn
rn.getIndex() = 0
)
or
exists(Function fd, DataFlow::ResultNode rn | GolangJwtKeyFunc::flow(fd.getARead(), _) |
exists(Function f, DataFlow::ResultNode rn |
GolangJwtKeyFunc::flow(f.getARead(), _) and
// sink is result of a method
sink = rn and
// the method is belong to a function in which is used as a JWT function key
rn.getRoot() = fd.getFuncDecl() and
rn.getRoot() = f.getFuncDecl() and
rn.getIndex() = 0
)
or
@@ -52,13 +53,13 @@ module GolangJwtKeyFuncConfig implements DataFlow::ConfigSig {
}
}
module JwtPaseWithConstantKey = TaintTracking::Global<JwtPaseWithConstantKeyConfig>;
module JwtParseWithConstantKey = TaintTracking::Global<JwtParseWithConstantKeyConfig>;
module GolangJwtKeyFunc = TaintTracking::Global<GolangJwtKeyFuncConfig>;
import JwtPaseWithConstantKey::PathGraph
import JwtParseWithConstantKey::PathGraph
from JwtPaseWithConstantKey::PathNode source, JwtPaseWithConstantKey::PathNode sink
where JwtPaseWithConstantKey::flowPath(source, sink)
from JwtParseWithConstantKey::PathNode source, JwtParseWithConstantKey::PathNode sink
where JwtParseWithConstantKey::flowPath(source, sink)
select sink.getNode(), source, sink, "This $@.", source.getNode(),
"Constant Key is used as JWT Secret key"

View File

@@ -0,0 +1,41 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
A JSON Web Token (JWT) is used for authenticating and managing users in an application.
</p>
<p>
Using a hard-coded secret key for parsing JWT tokens in open source projects
can leave the application using the token vulnerable to authentication bypasses.
</p>
<p>
A JWT token is safe for enforcing authentication and access control as long as it can't be forged by a malicious actor. However, when a project exposes this secret publicly, these seemingly unforgeable tokens can now be easily forged.
Since the authentication as well as access control is typically enforced through these JWT tokens, an attacker armed with the secret can create a valid authentication token for any user and may even gain access to other privileged parts of the application.
</p>
</overview>
<recommendation>
<p>
Generating a cryptographically secure secret key during application initialization and using this generated key for future JWT parsing requests can prevent this vulnerability.
</p>
</recommendation>
<example>
<p>
The following code uses a hard-coded string as a secret for parsing user provided JWTs. In this case, an attacker can very easily forge a token by using the hard-coded secret.
</p>
<sample src="ExampleGood.go" />
</example>
<references>
<li>
CVE-2022-0664:
<a href="https://nvd.nist.gov/vuln/detail/CVE-2022-0664">Use of Hard-coded Cryptographic Key in Go github.com/gravitl/netmaker prior to 0.8.5,0.9.4,0.10.0,0.10.1. </a>
</li>
</references>
</qhelp>

View File

@@ -3,13 +3,15 @@ package main
import (
"fmt"
"log"
"github.com/golang-jwt/jwt/v5"
)
func main() {
// BAD: only decode jwt without verification
notVerifyJWT(token)
// GOOD: decode with verification or verifiy plus decode
// GOOD: decode with verification or verify plus decode
notVerifyJWT(token)
VerifyJWT(token)
}

View File

@@ -16,8 +16,8 @@ module WithValidationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
predicate isSink(DataFlow::Node sink) {
sink = any(JwtParse parseUnverified).getTokenArg() or
sink = any(JwtParseWithKeyFunction parseUnverified).getTokenArg()
sink = any(JwtParse jwtParse).getTokenArg() or
sink = any(JwtParseWithKeyFunction jwtParseWithKeyFunction).getTokenArg()
}
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
@@ -52,4 +52,5 @@ import NoValidation::PathGraph
from NoValidation::PathNode source, NoValidation::PathNode sink
where NoValidation::flowPath(source, sink)
select sink.getNode(), source, sink, "This $@.", source.getNode(), "decode"
select sink.getNode(), source, sink, "This JWT is parsed without verification and received from $@.",
source.getNode(), "this user-controlled source"

View File

@@ -208,7 +208,7 @@ class GoJoseUnsafeClaims extends JwtUnverifiedParse {
}
/**
* Holds for general additioanl steps related to parsing the secret keys in `golang-jwt/jwt`,`dgrijalva/jwt-go` packages
* Holds for general additional steps related to parsing the secret keys in `golang-jwt/jwt`,`dgrijalva/jwt-go` packages
*/
predicate golangJwtIsAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(Function f, DataFlow::CallNode call |

View File

@@ -4,14 +4,15 @@ package jwt
import (
"fmt"
"github.com/go-jose/go-jose/v3/jwt"
"net/http"
"github.com/go-jose/go-jose/v3/jwt"
)
// NOT OK
var JwtKey = []byte("AllYourBase")
func main2(r *http.Request) {
// NOT OK
signedToken := r.URL.Query().Get("signedToken")
verifyJWT(signedToken)
}