mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
fix issues according to codereview
This commit is contained in:
@@ -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) {
|
||||
@@ -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"
|
||||
|
||||
41
go/ql/src/experimental/CWE-321-V2/HardcodedKeys.qhelp
Normal file
41
go/ql/src/experimental/CWE-321-V2/HardcodedKeys.qhelp
Normal 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>
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user