Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
50 changes: 50 additions & 0 deletions go/ql/src/experimental/CWE-321/HardcodedKeys.qhelp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!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 signing 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 cryptograhically secure secret key during application initialization and using this generated key for future JWT signing requests can prevent this vulnerability.
</p>

</recommendation>
<example>

<p>
The following code uses a hard-coded string as a secret for signing the tokens. In this case, an attacker can very easily forge a token by using the hard-coded secret.
</p>

<sample src="HardcodedKeysBad.go" />

</example>
<example>

<p>
In the following case, the application uses a programatically generated string as a secret for signing the tokens. In this case, since the secret can't be predicted, the code is secure. A function like `GenerateCryptoString` can be run to generate a secure secret key at the time of application installation/initialization. This generated key can then be used for all future signing requests.
</p>

<sample src="HardcodedKeysGood.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>
18 changes: 18 additions & 0 deletions go/ql/src/experimental/CWE-321/HardcodedKeys.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @name Use of a hardcoded key for signing JWT
* @description Using a fixed hardcoded key for signing JWT's can allow an attacker to compromise security.
* @kind path-problem
* @problem.severity error
* @id go/hardcoded-key
* @tags security
* external/cwe/cwe-321
*/

import go
import HardcodedKeysLib
import DataFlow::PathGraph

from HardcodedKeys::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "$@ is used to sign a JWT token.", source.getNode(),
"Hardcoded String"
9 changes: 9 additions & 0 deletions go/ql/src/experimental/CWE-321/HardcodedKeysBad.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
mySigningKey := []byte("AllYourBase")

claims := &jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Unix(1516239022, 0)),
Issuer: "test",
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
ss, err := token.SignedString(mySigningKey)
23 changes: 23 additions & 0 deletions go/ql/src/experimental/CWE-321/HardcodedKeysGood.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
func GenerateCryptoString(n int) (string, error) {
const chars = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"
ret := make([]byte, n)
for i := range ret {
num, err := crand.Int(crand.Reader, big.NewInt(int64(len(chars))))
if err != nil {
return "", err
}
ret[i] = chars[num.Int64()]
}
return string(ret), nil
}

mySigningKey := GenerateCryptoString(64)


claims := &jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Unix(1516239022, 0)),
Issuer: "test",
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
ss, err := token.SignedString(mySigningKey)
Loading