Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix issues according to codereview
  • Loading branch information
am0o0 committed Oct 10, 2023
commit 38b0ed81765118008fe1b0b878f1d7cf68c83a28
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
23 changes: 12 additions & 11 deletions go/ql/src/experimental/CWE-321-V2/HardCodedKeys.ql
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,27 @@
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) {
// first part is the JWT Parsing Functions that get a func type as an argument
// 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
)
Comment on lines +22 to +31
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two exists have a huge amount in common. It would be better to combine them into one exists.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think If I merge them it can be much longer that it is.

or
Expand All @@ -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 changes: 41 additions & 0 deletions go/ql/src/experimental/CWE-321-V2/HardcodedKeys.qhelp
Original file line number Diff line number Diff line change
@@ -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>
4 changes: 3 additions & 1 deletion go/ql/src/experimental/CWE-347/Example.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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"
Comment thread
owen-mc marked this conversation as resolved.
Outdated
2 changes: 1 addition & 1 deletion go/ql/src/experimental/frameworks/JWT.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
5 changes: 3 additions & 2 deletions go/ql/test/experimental/CWE-321-V2/go-jose.v3.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down