mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Go: Promote go/hardcoded-key from experimental
This commit is contained in:
6
go/ql/lib/ext/github.com.cristalhq.jwt.model.yml
Normal file
6
go/ql/lib/ext/github.com.cristalhq.jwt.model.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/cristalhq/jwt/$ANYVERSION", "", True, "NewSignerHS", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
7
go/ql/lib/ext/github.com.dgrijalva.jwt-go.model.yml
Normal file
7
go/ql/lib/ext/github.com.dgrijalva.jwt-go.model.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/dgrijalva/jwt-go", "Token", True, "SignedString", "", "", "Argument[0]", "credentials-key", "manual"]
|
||||
- ["github.com/dgrijalva/jwt-go", "SigningMethod", True, "Sign", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
7
go/ql/lib/ext/github.com.form3tech-oss.jwt-go.model.yml
Normal file
7
go/ql/lib/ext/github.com.form3tech-oss.jwt-go.model.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/form3tech-oss/jwt-go", "Token", True, "SignedString", "", "", "Argument[0]", "credentials-key", "manual"]
|
||||
- ["github.com/form3tech-oss/jwt-go", "SigningMethod", True, "Sign", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
6
go/ql/lib/ext/github.com.go-chi.jwtauth.model.yml
Normal file
6
go/ql/lib/ext/github.com.go-chi.jwtauth.model.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/go-chi/jwtauth/$ANYVERSION", "", True, "New", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
6
go/ql/lib/ext/github.com.go-kit.kit.auth.jwt.model.yml
Normal file
6
go/ql/lib/ext/github.com.go-kit.kit.auth.jwt.model.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/go-kit/kit/auth/jwt", "", True, "NewSigner", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
7
go/ql/lib/ext/github.com.golang-jwt.jwt.model.yml
Normal file
7
go/ql/lib/ext/github.com.golang-jwt.jwt.model.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/golang-jwt/jwt/$ANYVERSION", "Token", True, "SignedString", "", "", "Argument[0]", "credentials-key", "manual"]
|
||||
- ["github.com/golang-jwt/jwt/$ANYVERSION", "SigningMethod", True, "Sign", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/kataras/iris/$ANYVERSION/middleware/jwt", "", True, "NewSigner", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
10
go/ql/lib/ext/github.com.kataras.jwt.model.yml
Normal file
10
go/ql/lib/ext/github.com.kataras.jwt.model.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/kataras/jwt", "Keys", True, "Register", "", "", "Argument[3]", "credentials-key", "manual"]
|
||||
- ["github.com/kataras/jwt", "", True, "Sign", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
- ["github.com/kataras/jwt", "", True, "SignEncrypted", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
- ["github.com/kataras/jwt", "", True, "SignEncryptedWithHeader", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
- ["github.com/kataras/jwt", "", True, "SignWithHeader", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
6
go/ql/lib/ext/github.com.lestrrat-go.jwx.jwk.model.yml
Normal file
6
go/ql/lib/ext/github.com.lestrrat-go.jwx.jwk.model.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/lestrrat-go/jwx/$ANYVERSION/jwk", "", True, "New", "", "", "Argument[0]", "credentials-key", "manual"]
|
||||
6
go/ql/lib/ext/github.com.lestrrat-go.jwx.model.yml
Normal file
6
go/ql/lib/ext/github.com.lestrrat-go.jwx.model.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/lestrrat-go/jwx", "", True, "New", "", "", "Argument[0]", "credentials-key", "manual"]
|
||||
6
go/ql/lib/ext/github.com.lestrrat.go-jwx.jwk.model.yml
Normal file
6
go/ql/lib/ext/github.com.lestrrat.go-jwx.jwk.model.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/lestrrat/go-jwx/jwk", "", True, "New", "", "", "Argument[0]", "credentials-key", "manual"]
|
||||
7
go/ql/lib/ext/github.com.ory.fosite.token.jwt.model.yml
Normal file
7
go/ql/lib/ext/github.com.ory.fosite.token.jwt.model.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["github.com/ory/fosite/token/jwt", "Token", True, "SignedString", "", "", "Argument[0]", "credentials-key", "manual"]
|
||||
- ["github.com/ory/fosite/token/jwt", "SigningMethod", True, "Sign", "", "", "Argument[1]", "credentials-key", "manual"]
|
||||
6
go/ql/lib/ext/math.big.model.yml
Normal file
6
go/ql/lib/ext/math.big.model.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/go-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["math/big", "Int", False, "Int64", "", "", "Argument[-1]", "ReturnValue[0]", "taint", "manual"]
|
||||
158
go/ql/lib/semmle/go/security/HardcodedCredentials.qll
Normal file
158
go/ql/lib/semmle/go/security/HardcodedCredentials.qll
Normal file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
* hardcoded credentials, as well as extension points
|
||||
* for adding your own.
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.StringOps
|
||||
private import semmle.go.dataflow.ExternalFlow
|
||||
private import semmle.go.security.Jwt
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
* hardcoded credentials, as well as extension points
|
||||
* for adding your own.
|
||||
*/
|
||||
module HardcodedCredentials {
|
||||
/** A data flow source for hardcoded credentials. */
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/** A data flow sink for hardcoded credentials. */
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/** A sanitizer for hardcoded credentials. */
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about hardcoded credentials. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
/** A hardcoded string literal as a source for hardcoded credentials. */
|
||||
private class HardcodedStringSource extends Source {
|
||||
HardcodedStringSource() { this.asExpr() instanceof StringLit }
|
||||
}
|
||||
|
||||
/** A use of a credential. */
|
||||
private class CredentialsSink extends Sink {
|
||||
CredentialsSink() { exists(string s | s.matches("credentials-%") | sinkNode(this, s)) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the guard `g` in its branch `branch` validates the expression `e`
|
||||
* by comparing it to a disallowed literal.
|
||||
*/
|
||||
private predicate constantValueCheck(DataFlow::Node g, Expr e, boolean branch) {
|
||||
exists(Literal lit, DataFlow::EqualityTestNode eq | eq = g |
|
||||
eq.getAnOperand().asExpr() = e and
|
||||
eq.getAnOperand().asExpr() = lit and
|
||||
e != lit and
|
||||
branch = eq.getPolarity().booleanNot()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A value validated by comparing it to a disallowed constant value.
|
||||
* For example, in the context `if key != "invalid_key" { ... }`,
|
||||
* if `"invalid_key"` is indeed the only dangerous key then guarded uses of `key` are likely
|
||||
* to be safe.
|
||||
*/
|
||||
private class CompareExprSanitizer extends Sanitizer {
|
||||
CompareExprSanitizer() {
|
||||
this = DataFlow::BarrierGuard<constantValueCheck/3>::getABarrierNode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value returned with an error.
|
||||
*
|
||||
* Typically this means contexts like `return "", errors.New("Oh no")`,
|
||||
* where we can be reasonably confident downstream users will not mistake
|
||||
* that empty string for a usable key.
|
||||
*/
|
||||
private class ReturnedAlongsideErrorSanitizer extends Sanitizer {
|
||||
ReturnedAlongsideErrorSanitizer() {
|
||||
exists(ReturnStmt r, DataFlow::CallNode c |
|
||||
c.getTarget().hasQualifiedName("errors", "New") and
|
||||
r.getNumChild() > 1 and
|
||||
r.getAChild() = c.getAResult().getASuccessor*().asExpr() and
|
||||
r.getAChild() = this.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value returned alongside an error-value that is known
|
||||
* to be non-nil by virtue of a guarding check.
|
||||
*
|
||||
* For example, `if err != nil { return "", err }` is unlikely to be
|
||||
* contributing a dangerous hardcoded key.
|
||||
*/
|
||||
private class ReturnedAlongsideErrorSanitizerGuard extends Sanitizer {
|
||||
ReturnedAlongsideErrorSanitizerGuard() {
|
||||
exists(ControlFlow::ConditionGuardNode guard, SsaWithFields errorVar, ReturnStmt r |
|
||||
guard.ensuresNeq(errorVar.getAUse(), Builtin::nil().getARead()) and
|
||||
guard.dominates(this.getBasicBlock()) and
|
||||
r.getExpr(1) = errorVar.getAUse().asExpr() and
|
||||
this.asExpr() = r.getExpr(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The result of a formatting string call. */
|
||||
private class FormattingSanitizer extends Sanitizer {
|
||||
FormattingSanitizer() { any(StringOps::Formatting::StringFormatCall s).getAResult() = this }
|
||||
}
|
||||
|
||||
private string getRandIntFunctionName() {
|
||||
result =
|
||||
[
|
||||
"ExpFloat64", "Float32", "Float64", "Int", "Int31", "Int31n", "Int63", "Int63n", "Intn",
|
||||
"NormFloat64", "Uint32", "Uint64"
|
||||
]
|
||||
}
|
||||
|
||||
private DataFlow::CallNode getARandIntCall() {
|
||||
exists(Function f | f = result.getTarget() |
|
||||
f.hasQualifiedName("math/rand", getRandIntFunctionName()) or
|
||||
f.(Method).hasQualifiedName("math/rand", "Rand", getRandIntFunctionName()) or
|
||||
f.hasQualifiedName("crypto/rand", "Int")
|
||||
)
|
||||
}
|
||||
|
||||
private DataFlow::CallNode getARandReadCall() {
|
||||
result.getTarget().hasQualifiedName("crypto/rand", "Read")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint flows in one local step from `prev` to `succ`, or
|
||||
* through a binary operation such as a modulo `%` operation or an addition `+` operation.
|
||||
*/
|
||||
private predicate localTaintStepIncludingBinaryExpr(DataFlow::Node prev, DataFlow::Node succ) {
|
||||
TaintTracking::localTaintStep(prev, succ)
|
||||
or
|
||||
exists(BinaryExpr b | b.getAnOperand() = prev.asExpr() | succ.asExpr() = b)
|
||||
}
|
||||
|
||||
/** A read from a slice with a random index. */
|
||||
private class RandSliceSanitizer extends Sanitizer, DataFlow::ElementReadNode {
|
||||
RandSliceSanitizer() {
|
||||
exists(DataFlow::Node randomValue, DataFlow::Node index |
|
||||
randomValue = getARandIntCall().getAResult()
|
||||
or
|
||||
randomValue.(DataFlow::PostUpdateNode).getPreUpdateNode() =
|
||||
getARandReadCall().getArgument(0)
|
||||
|
|
||||
localTaintStepIncludingBinaryExpr*(randomValue, index) and
|
||||
this.reads(_, index)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
44
go/ql/lib/semmle/go/security/Jwt.qll
Normal file
44
go/ql/lib/semmle/go/security/Jwt.qll
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Provides classes and predicates for reasoning about JSON Web Tokens (JWT).
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.security.HardcodedCredentials
|
||||
|
||||
private class IrisJwt extends HardcodedCredentials::Sink {
|
||||
IrisJwt() {
|
||||
exists(Field f |
|
||||
f.hasQualifiedName(package("github.com/kataras/iris", "middleware/jwt"), "Signer", "Key") and
|
||||
f.getAWrite().getRhs() = this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class GogfJwtSign extends HardcodedCredentials::Sink {
|
||||
GogfJwtSign() {
|
||||
exists(Field f |
|
||||
f.hasQualifiedName(package("github.com/gogf/gf-jwt", ""), "GfJWTMiddleware", "Key") and
|
||||
f.getAWrite().getRhs() = this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class GinJwtSign extends HardcodedCredentials::Sink {
|
||||
GinJwtSign() {
|
||||
exists(Field f |
|
||||
f.hasQualifiedName(package("github.com/appleboy/gin-jwt", ""), "GinJWTMiddleware", "Key") and
|
||||
f.getAWrite().getRhs() = this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class SquareJoseKey extends HardcodedCredentials::Sink {
|
||||
SquareJoseKey() {
|
||||
exists(Field f, string pkg |
|
||||
pkg = ["github.com/square/go-jose/v3", "gopkg.in/square/go-jose.v2"]
|
||||
|
|
||||
f.hasQualifiedName(pkg, ["Recipient", "SigningKey"], "Key") and
|
||||
f.getAWrite().getRhs() = this
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.HardcodedCredentials
|
||||
import semmle.go.security.SensitiveActions
|
||||
|
||||
/**
|
||||
@@ -31,22 +32,35 @@ predicate isSensitive(DataFlow::Node sink, SensitiveExpr::Classification type) {
|
||||
)
|
||||
}
|
||||
|
||||
from DataFlow::Node source, string message, DataFlow::Node sink, SensitiveExpr::Classification type
|
||||
where
|
||||
predicate sensitiveAssignment(
|
||||
DataFlow::Node source, DataFlow::Node sink, SensitiveExpr::Classification type
|
||||
) {
|
||||
exists(string val | val = source.getStringValue() and val != "" |
|
||||
isSensitive(sink, type) and
|
||||
DataFlow::localFlow(source, sink) and
|
||||
isSensitive(sink, type) and
|
||||
// allow obvious dummy/test values
|
||||
not PasswordHeuristics::isDummyPassword(val) and
|
||||
not sink.asExpr().(Ident).getName().regexpMatch(HeuristicNames::notSensitive())
|
||||
) and
|
||||
)
|
||||
}
|
||||
|
||||
predicate hardcodedPrivateKey(DataFlow::Node node, SensitiveExpr::Classification type) {
|
||||
node.getStringValue()
|
||||
.regexpMatch("(?s)-+BEGIN\\b.*\\bPRIVATE KEY-+.+-+END\\b.*\\bPRIVATE KEY-+\n?") and
|
||||
(node.asExpr() instanceof StringLit or node.asExpr() instanceof AddExpr) and
|
||||
type = SensitiveExpr::certificate()
|
||||
}
|
||||
|
||||
from DataFlow::Node source, string message, DataFlow::Node sink, SensitiveExpr::Classification type
|
||||
where
|
||||
sensitiveAssignment(source, sink, type) and
|
||||
message = "Hard-coded $@."
|
||||
or
|
||||
source
|
||||
.getStringValue()
|
||||
.regexpMatch("(?s)-+BEGIN\\b.*\\bPRIVATE KEY-+.+-+END\\b.*\\bPRIVATE KEY-+\n?") and
|
||||
(source.asExpr() instanceof StringLit or source.asExpr() instanceof AddExpr) and
|
||||
sink = source and
|
||||
type = SensitiveExpr::certificate() and
|
||||
hardcodedPrivateKey(source, type) and
|
||||
source = sink and
|
||||
message = "Hard-coded private key."
|
||||
or
|
||||
HardcodedCredentials::Flow::flow(source, sink) and
|
||||
type = SensitiveExpr::password() and
|
||||
message = "Hard-coded credential."
|
||||
select sink, message, source, type.toString()
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* The query "Use of a hardcoded key for signing JWT" (`go/hardcoded-key`) has been promoted from experimental to the main query pack. Its results will now appear by default as part of `go/hardcoded-credentials`. This query was originally [submitted as an experimental query by @porcupineyhairs](https://github.com/github/codeql/pull/9378).
|
||||
@@ -1,50 +0,0 @@
|
||||
<!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 cryptographically 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>
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
* experimental
|
||||
* external/cwe/cwe-321
|
||||
*/
|
||||
|
||||
import go
|
||||
import HardcodedKeysLib
|
||||
import HardcodedKeys::Flow::PathGraph
|
||||
|
||||
from HardcodedKeys::Flow::PathNode source, HardcodedKeys::Flow::PathNode sink
|
||||
where HardcodedKeys::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "$@ is used to sign a JWT token.", source.getNode(),
|
||||
"Hardcoded String"
|
||||
@@ -1,15 +0,0 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
func bad() {
|
||||
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)
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func good() {
|
||||
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)
|
||||
}
|
||||
@@ -1,389 +0,0 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
* JWT token signing vulnerabilities as well as extension points
|
||||
* for adding your own.
|
||||
*/
|
||||
|
||||
import go
|
||||
import StringOps
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
* JWT token signing vulnerabilities as well as extension points
|
||||
* for adding your own.
|
||||
*/
|
||||
module HardcodedKeys {
|
||||
/**
|
||||
* A data flow source for JWT token signing vulnerabilities.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for JWT token signing vulnerabilities.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer for JWT token signing vulnerabilities.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
private predicate isTestCode(Expr e) {
|
||||
e.getFile().getAbsolutePath().toLowerCase().matches("%test%") and
|
||||
not e.getFile().getAbsolutePath().toLowerCase().matches("%ql/test%")
|
||||
}
|
||||
|
||||
private predicate isDemoCode(Expr e) {
|
||||
e.getFile().getAbsolutePath().toLowerCase().matches(["%mock%", "%demo%", "%example%"])
|
||||
}
|
||||
|
||||
/**
|
||||
* A hardcoded string literal as a source for JWT token signing vulnerabilities.
|
||||
*/
|
||||
private class HardcodedStringSource extends Source {
|
||||
HardcodedStringSource() {
|
||||
this.asExpr() instanceof StringLit and
|
||||
not (isTestCode(this.asExpr()) or isDemoCode(this.asExpr()))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression used to sign JWT tokens as a sink for JWT token signing vulnerabilities.
|
||||
*/
|
||||
private class GolangJwtSign extends Sink {
|
||||
GolangJwtSign() {
|
||||
exists(string pkg |
|
||||
pkg =
|
||||
[
|
||||
"github.com/golang-jwt/jwt/v4", "github.com/dgrijalva/jwt-go",
|
||||
"github.com/form3tech-oss/jwt-go", "github.com/ory/fosite/token/jwt"
|
||||
]
|
||||
|
|
||||
exists(DataFlow::MethodCallNode m |
|
||||
// Models the `SignedString` method
|
||||
// `func (t *Token) SignedString(key interface{}) (string, error)`
|
||||
m.getTarget().hasQualifiedName(pkg, "Token", "SignedString") and
|
||||
this = m.getArgument(0)
|
||||
or
|
||||
// Model the `Sign` method of the `SigningMethod` interface
|
||||
// type SigningMethod interface {
|
||||
// Verify(signingString, signature string, key interface{}) error
|
||||
// Sign(signingString string, key interface{}) (string, error)
|
||||
// Alg() string
|
||||
// }
|
||||
m.getTarget().hasQualifiedName(pkg, "SigningMethod", "Sign") and
|
||||
this = m.getArgument(1)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class KatarasJwt extends Sink {
|
||||
KatarasJwt() {
|
||||
exists(string pkg |
|
||||
pkg = package("github.com/kataras/jwt", "") and
|
||||
(
|
||||
exists(DataFlow::MethodCallNode m |
|
||||
// Model the `Register` method of the type `Keys`
|
||||
// func (keys Keys) Register(alg Alg, kid string, pubKey PublicKey, privKey PrivateKey)
|
||||
m.getTarget().hasQualifiedName(pkg, "Keys", "Register")
|
||||
|
|
||||
this = m.getArgument(3)
|
||||
)
|
||||
or
|
||||
exists(DataFlow::CallNode m, string names |
|
||||
// Model the `Sign` method of the `SigningMethod` interface
|
||||
// func Sign(alg Alg, key PrivateKey, claims interface{}, opts ...SignOption) ([]byte, error)
|
||||
// func SignEncrypted(alg Alg, key PrivateKey, encrypt InjectFunc, claims interface{}, ...) ([]byte, error)
|
||||
// func SignEncryptedWithHeader(alg Alg, key PrivateKey, encrypt InjectFunc, claims interface{}, ...) ([]byte, error)
|
||||
// func SignWithHeader(alg Alg, key PrivateKey, claims interface{}, customHeader interface{}, ...) ([]byte, error)
|
||||
m.getTarget().hasQualifiedName(pkg, names) and
|
||||
names = ["Sign", "SignEncrypted", "SignEncryptedWithHeader", "SignWithHeader"]
|
||||
|
|
||||
this = m.getArgument(1)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class IrisJwt extends Sink {
|
||||
IrisJwt() {
|
||||
exists(string pkg |
|
||||
pkg = "github.com/kataras/iris/v12/middleware/jwt" and
|
||||
(
|
||||
exists(DataFlow::CallNode m |
|
||||
//func NewSigner(signatureAlg Alg, signatureKey interface{}, maxAge time.Duration) *Signer
|
||||
m.getTarget().hasQualifiedName(pkg, "NewSigner")
|
||||
|
|
||||
this = m.getArgument(1)
|
||||
)
|
||||
or
|
||||
exists(Field f |
|
||||
// Models the `key` field of the `Signer` type
|
||||
// https://github.com/kataras/iris/blob/dccd57263617f5ca95d7621acfadf9dd37752dd6/middleware/jwt/signer.go#L17
|
||||
f.hasQualifiedName(pkg, "Signer", "Key") and
|
||||
f.getAWrite().getRhs() = this
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class GogfJwtSign extends Sink {
|
||||
GogfJwtSign() {
|
||||
exists(Field f, string pkg |
|
||||
pkg = package("github.com/gogf/gf-jwt", "") and
|
||||
// https://github.com/gogf/gf-jwt/blob/40503f05bc0a2bcd7aeba550163112afbb5c221f/auth_jwt.go#L27
|
||||
f.hasQualifiedName(pkg, "GfJWTMiddleware", "Key") and
|
||||
f.getAWrite().getRhs() = this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class GinJwtSign extends Sink {
|
||||
GinJwtSign() {
|
||||
exists(Field f |
|
||||
// https://pkg.go.dev/github.com/appleboy/gin-jwt/v2#GinJWTMiddleware
|
||||
f.hasQualifiedName("github.com/appleboy/gin-jwt/v2", "GinJWTMiddleware", "Key") and
|
||||
f.getAWrite().getRhs() = this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class SquareJoseKey extends Sink {
|
||||
SquareJoseKey() {
|
||||
exists(Field f, string pkg |
|
||||
// type Recipient struct {
|
||||
// Algorithm KeyAlgorithm
|
||||
// Key interface{}
|
||||
// KeyID string
|
||||
// PBES2Count int
|
||||
// PBES2Salt []byte
|
||||
// }
|
||||
// type SigningKey struct {
|
||||
// Algorithm SignatureAlgorithm
|
||||
// Key interface{}
|
||||
// }
|
||||
f.hasQualifiedName(pkg, ["Recipient", "SigningKey"], "Key") and
|
||||
f.getAWrite().getRhs() = this
|
||||
|
|
||||
pkg = ["github.com/square/go-jose/v3", "gopkg.in/square/go-jose.v2"]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class CrystalHqJwtSigner extends Sink {
|
||||
CrystalHqJwtSigner() {
|
||||
exists(DataFlow::CallNode m |
|
||||
// `func NewSignerHS(alg Algorithm, key []byte) (Signer, error)`
|
||||
m.getTarget().hasQualifiedName("github.com/cristalhq/jwt/v3", "NewSignerHS")
|
||||
|
|
||||
this = m.getArgument(1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class GoKitJwt extends Sink {
|
||||
GoKitJwt() {
|
||||
exists(DataFlow::CallNode m |
|
||||
// `func NewSigner(kid string, key []byte, method jwt.SigningMethod, claims jwt.Claims) endpoint.Middleware`
|
||||
m.getTarget().hasQualifiedName("github.com/go-kit/kit/auth/jwt", "NewSigner")
|
||||
|
|
||||
this = m.getArgument(1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class LestrratJwk extends Sink {
|
||||
LestrratJwk() {
|
||||
exists(DataFlow::CallNode m, string pkg |
|
||||
pkg.matches([
|
||||
"github.com/lestrrat-go/jwx", "github.com/lestrrat/go-jwx/jwk",
|
||||
"github.com/lestrrat-go/jwx%/jwk"
|
||||
]) and
|
||||
// `func New(key interface{}) (Key, error)`
|
||||
m.getTarget().hasQualifiedName(pkg, "New")
|
||||
|
|
||||
this = m.getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes any other use of an operand to a comparison, on the assumption that this may filter
|
||||
* out special constant values -- for example, in context `if key != "invalid_key" { ... }`,
|
||||
* if `"invalid_key"` is indeed the only dangerous key then guarded uses of `key` are likely
|
||||
* to be safe.
|
||||
*
|
||||
* TODO: Before promoting this query look at replacing this with something more principled.
|
||||
*/
|
||||
private class CompareExprSanitizer extends Sanitizer {
|
||||
CompareExprSanitizer() {
|
||||
exists(ComparisonExpr c |
|
||||
c.getAnOperand().getGlobalValueNumber() = this.asExpr().getGlobalValueNumber() and
|
||||
not this.asExpr() instanceof Literal
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks anything returned with an error as a sanitized.
|
||||
*
|
||||
* Typically this means contexts like `return "", errors.New("Oh no")`,
|
||||
* where we can be reasonably confident downstream users won't mistake
|
||||
* that empty string for a usable key.
|
||||
*/
|
||||
private class ReturnedAlongsideErrorSanitizer extends Sanitizer {
|
||||
ReturnedAlongsideErrorSanitizer() {
|
||||
exists(ReturnStmt r, DataFlow::CallNode c |
|
||||
c.getTarget().hasQualifiedName("errors", "New") and
|
||||
r.getNumChild() > 1 and
|
||||
r.getAChild() = c.getAResult().getASuccessor*().asExpr() and
|
||||
r.getAChild() = this.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks anything returned alongside an error-value that is known
|
||||
* to be non-nil by virtue of a guarding check as harmless.
|
||||
*
|
||||
* For example, `if err != nil { return "", err }` is unlikely to be
|
||||
* contributing a dangerous hardcoded key.
|
||||
*/
|
||||
private class ReturnedAlongsideErrorSanitizerGuard extends Sanitizer {
|
||||
ReturnedAlongsideErrorSanitizerGuard() {
|
||||
exists(ControlFlow::ConditionGuardNode guard, SsaWithFields errorVar, ReturnStmt r |
|
||||
guard.ensuresNeq(errorVar.getAUse(), Builtin::nil().getARead()) and
|
||||
guard.dominates(this.getBasicBlock()) and
|
||||
r.getExpr(1) = errorVar.getAUse().asExpr() and
|
||||
this.asExpr() = r.getExpr(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Mark any formatting string call as a sanitizer */
|
||||
private class FormattingSanitizer extends Sanitizer {
|
||||
FormattingSanitizer() { exists(Formatting::StringFormatCall s | s.getAResult() = this) }
|
||||
}
|
||||
|
||||
private string getRandIntFunctionName() {
|
||||
result =
|
||||
[
|
||||
"ExpFloat64", "Float32", "Float64", "Int", "Int31", "Int31n", "Int63", "Int63n", "Intn",
|
||||
"NormFloat64", "Uint32", "Uint64"
|
||||
]
|
||||
}
|
||||
|
||||
private DataFlow::CallNode getARandIntCall() {
|
||||
result.getTarget().hasQualifiedName("math/rand", getRandIntFunctionName()) or
|
||||
result.getTarget().(Method).hasQualifiedName("math/rand", "Rand", getRandIntFunctionName()) or
|
||||
result.getTarget().hasQualifiedName("crypto/rand", "Int")
|
||||
}
|
||||
|
||||
private DataFlow::CallNode getARandReadCall() {
|
||||
result.getTarget().hasQualifiedName("crypto/rand", "Read")
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark any taint arising from a read on a tainted slice with a random index as a
|
||||
* sanitizer for all instances of the taint
|
||||
*/
|
||||
private class RandSliceSanitizer extends Sanitizer {
|
||||
RandSliceSanitizer() {
|
||||
exists(DataFlow::Node randomValue, DataFlow::Node index |
|
||||
// Sanitize flows like this:
|
||||
// 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
|
||||
// }
|
||||
randomValue = getARandIntCall().getAResult()
|
||||
or
|
||||
// Sanitize flows like :
|
||||
// func GenerateRandomString(size int) string {
|
||||
// var bytes = make([]byte, size)
|
||||
// rand.Read(bytes)
|
||||
// for i, x := range bytes {
|
||||
// bytes[i] = characters[x%byte(len(characters))]
|
||||
// }
|
||||
// return string(bytes)
|
||||
// }
|
||||
randomValue =
|
||||
any(DataFlow::PostUpdateNode pun |
|
||||
pun.getPreUpdateNode() = getARandReadCall().getArgument(0)
|
||||
)
|
||||
|
|
||||
TaintTracking::localTaint(randomValue, index) and
|
||||
this.(DataFlow::ElementReadNode).reads(_, index)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Models flow from a call to `Int64` if the receiver is tainted
|
||||
*/
|
||||
private class BigIntFlow extends TaintTracking::FunctionModel {
|
||||
BigIntFlow() { this.(Method).hasQualifiedName("math/big", "Int", "Int64") }
|
||||
|
||||
override predicate hasTaintFlow(DataFlow::FunctionInput inp, DataFlow::FunctionOutput outp) {
|
||||
inp.isReceiver() and
|
||||
outp.isResult(0)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Models taint flow through a binary operation such as a
|
||||
* modulo `%` operation or an addition `+` operation
|
||||
*/
|
||||
|
||||
private class BinExpAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
// This is required to model the sanitizers for the `HardcodedKeys` query.
|
||||
// This is required to correctly detect a sanitizer such as the one shown below.
|
||||
// func GenerateRandomString(size int) string {
|
||||
// var bytes = make([]byte, size)
|
||||
// rand.Read(bytes)
|
||||
// for i, x := range bytes {
|
||||
// bytes[i] = characters[x%byte(len(characters))]
|
||||
// }
|
||||
// return string(bytes)
|
||||
// }
|
||||
override predicate step(DataFlow::Node prev, DataFlow::Node succ) {
|
||||
exists(BinaryExpr b | b.getAnOperand() = prev.asExpr() | succ.asExpr() = b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A configuration depicting taint flow for studying JWT token signing vulnerabilities.
|
||||
*/
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "Hard-coded JWT Signing Key" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer }
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about JWT token signing vulnerabilities. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
edges
|
||||
| HardcodedKeysBad.go:11:18:11:38 | type conversion | HardcodedKeysBad.go:19:28:19:39 | mySigningKey | provenance | |
|
||||
| HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" | HardcodedKeysBad.go:11:18:11:38 | type conversion | provenance | |
|
||||
| main.go:33:18:33:31 | type conversion | main.go:42:28:42:39 | mySigningKey | provenance | |
|
||||
| main.go:33:25:33:30 | "key1" | main.go:33:18:33:31 | type conversion | provenance | |
|
||||
| main.go:50:23:50:28 | "key2" | main.go:50:16:50:29 | type conversion | provenance | |
|
||||
| main.go:68:9:68:22 | type conversion | main.go:69:44:69:46 | key | provenance | |
|
||||
| main.go:68:16:68:21 | `key3` | main.go:68:9:68:22 | type conversion | provenance | |
|
||||
| main.go:73:9:73:22 | type conversion | main.go:74:66:74:68 | key | provenance | |
|
||||
| main.go:73:16:73:21 | "key4" | main.go:73:9:73:22 | type conversion | provenance | |
|
||||
| main.go:77:10:77:23 | type conversion | main.go:82:15:82:18 | key2 | provenance | |
|
||||
| main.go:77:17:77:22 | "key5" | main.go:77:10:77:23 | type conversion | provenance | |
|
||||
| main.go:88:9:88:22 | type conversion | main.go:92:41:92:43 | key | provenance | |
|
||||
| main.go:88:16:88:21 | "key6" | main.go:88:9:88:22 | type conversion | provenance | |
|
||||
| main.go:97:10:97:23 | type conversion | main.go:99:66:99:69 | key2 | provenance | |
|
||||
| main.go:97:17:97:22 | "key7" | main.go:97:10:97:23 | type conversion | provenance | |
|
||||
| main.go:105:9:105:22 | type conversion | main.go:110:30:110:32 | key | provenance | |
|
||||
| main.go:105:16:105:21 | "key8" | main.go:105:9:105:22 | type conversion | provenance | |
|
||||
| main.go:114:15:114:28 | type conversion | main.go:115:16:115:24 | sharedKey | provenance | |
|
||||
| main.go:114:22:114:27 | "key9" | main.go:114:15:114:28 | type conversion | provenance | |
|
||||
| main.go:118:23:118:37 | type conversion | main.go:121:16:121:30 | sharedKeyglobal | provenance | |
|
||||
| main.go:118:30:118:36 | "key10" | main.go:118:23:118:37 | type conversion | provenance | |
|
||||
| main.go:127:27:127:33 | "key11" | main.go:127:20:127:34 | type conversion | provenance | |
|
||||
| main.go:142:14:142:28 | type conversion | main.go:144:39:144:46 | mySecret | provenance | |
|
||||
| main.go:142:21:142:27 | "key12" | main.go:142:14:142:28 | type conversion | provenance | |
|
||||
| main.go:149:14:149:28 | type conversion | main.go:153:11:153:18 | mySecret | provenance | |
|
||||
| main.go:149:21:149:27 | "key13" | main.go:149:14:149:28 | type conversion | provenance | |
|
||||
| main.go:160:12:160:26 | type conversion | main.go:161:34:161:39 | secret | provenance | |
|
||||
| main.go:160:19:160:25 | "key14" | main.go:160:12:160:26 | type conversion | provenance | |
|
||||
| main.go:166:12:166:26 | type conversion | main.go:167:32:167:37 | secret | provenance | |
|
||||
| main.go:166:19:166:25 | "key15" | main.go:166:12:166:26 | type conversion | provenance | |
|
||||
| main.go:172:12:172:26 | type conversion | main.go:173:41:173:46 | secret | provenance | |
|
||||
| main.go:172:19:172:25 | "key16" | main.go:172:12:172:26 | type conversion | provenance | |
|
||||
| main.go:178:12:178:26 | type conversion | main.go:179:51:179:56 | secret | provenance | |
|
||||
| main.go:178:19:178:25 | "key17" | main.go:178:12:178:26 | type conversion | provenance | |
|
||||
| main.go:184:12:184:26 | type conversion | main.go:185:42:185:47 | secret | provenance | |
|
||||
| main.go:184:19:184:25 | "key18" | main.go:184:12:184:26 | type conversion | provenance | |
|
||||
| main.go:190:12:190:26 | type conversion | main.go:193:33:193:38 | secret | provenance | |
|
||||
| main.go:190:19:190:25 | "key19" | main.go:190:12:190:26 | type conversion | provenance | |
|
||||
| sanitizer.go:17:9:17:21 | type conversion | sanitizer.go:18:44:18:46 | key | provenance | |
|
||||
| sanitizer.go:17:16:17:20 | `key` | sanitizer.go:17:9:17:21 | type conversion | provenance | |
|
||||
nodes
|
||||
| HardcodedKeysBad.go:11:18:11:38 | type conversion | semmle.label | type conversion |
|
||||
| HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" | semmle.label | "AllYourBase" |
|
||||
| HardcodedKeysBad.go:19:28:19:39 | mySigningKey | semmle.label | mySigningKey |
|
||||
| main.go:33:18:33:31 | type conversion | semmle.label | type conversion |
|
||||
| main.go:33:25:33:30 | "key1" | semmle.label | "key1" |
|
||||
| main.go:42:28:42:39 | mySigningKey | semmle.label | mySigningKey |
|
||||
| main.go:50:16:50:29 | type conversion | semmle.label | type conversion |
|
||||
| main.go:50:23:50:28 | "key2" | semmle.label | "key2" |
|
||||
| main.go:68:9:68:22 | type conversion | semmle.label | type conversion |
|
||||
| main.go:68:16:68:21 | `key3` | semmle.label | `key3` |
|
||||
| main.go:69:44:69:46 | key | semmle.label | key |
|
||||
| main.go:73:9:73:22 | type conversion | semmle.label | type conversion |
|
||||
| main.go:73:16:73:21 | "key4" | semmle.label | "key4" |
|
||||
| main.go:74:66:74:68 | key | semmle.label | key |
|
||||
| main.go:77:10:77:23 | type conversion | semmle.label | type conversion |
|
||||
| main.go:77:17:77:22 | "key5" | semmle.label | "key5" |
|
||||
| main.go:82:15:82:18 | key2 | semmle.label | key2 |
|
||||
| main.go:88:9:88:22 | type conversion | semmle.label | type conversion |
|
||||
| main.go:88:16:88:21 | "key6" | semmle.label | "key6" |
|
||||
| main.go:92:41:92:43 | key | semmle.label | key |
|
||||
| main.go:97:10:97:23 | type conversion | semmle.label | type conversion |
|
||||
| main.go:97:17:97:22 | "key7" | semmle.label | "key7" |
|
||||
| main.go:99:66:99:69 | key2 | semmle.label | key2 |
|
||||
| main.go:105:9:105:22 | type conversion | semmle.label | type conversion |
|
||||
| main.go:105:16:105:21 | "key8" | semmle.label | "key8" |
|
||||
| main.go:110:30:110:32 | key | semmle.label | key |
|
||||
| main.go:114:15:114:28 | type conversion | semmle.label | type conversion |
|
||||
| main.go:114:22:114:27 | "key9" | semmle.label | "key9" |
|
||||
| main.go:115:16:115:24 | sharedKey | semmle.label | sharedKey |
|
||||
| main.go:118:23:118:37 | type conversion | semmle.label | type conversion |
|
||||
| main.go:118:30:118:36 | "key10" | semmle.label | "key10" |
|
||||
| main.go:121:16:121:30 | sharedKeyglobal | semmle.label | sharedKeyglobal |
|
||||
| main.go:127:20:127:34 | type conversion | semmle.label | type conversion |
|
||||
| main.go:127:27:127:33 | "key11" | semmle.label | "key11" |
|
||||
| main.go:142:14:142:28 | type conversion | semmle.label | type conversion |
|
||||
| main.go:142:21:142:27 | "key12" | semmle.label | "key12" |
|
||||
| main.go:144:39:144:46 | mySecret | semmle.label | mySecret |
|
||||
| main.go:149:14:149:28 | type conversion | semmle.label | type conversion |
|
||||
| main.go:149:21:149:27 | "key13" | semmle.label | "key13" |
|
||||
| main.go:153:11:153:18 | mySecret | semmle.label | mySecret |
|
||||
| main.go:160:12:160:26 | type conversion | semmle.label | type conversion |
|
||||
| main.go:160:19:160:25 | "key14" | semmle.label | "key14" |
|
||||
| main.go:161:34:161:39 | secret | semmle.label | secret |
|
||||
| main.go:166:12:166:26 | type conversion | semmle.label | type conversion |
|
||||
| main.go:166:19:166:25 | "key15" | semmle.label | "key15" |
|
||||
| main.go:167:32:167:37 | secret | semmle.label | secret |
|
||||
| main.go:172:12:172:26 | type conversion | semmle.label | type conversion |
|
||||
| main.go:172:19:172:25 | "key16" | semmle.label | "key16" |
|
||||
| main.go:173:41:173:46 | secret | semmle.label | secret |
|
||||
| main.go:178:12:178:26 | type conversion | semmle.label | type conversion |
|
||||
| main.go:178:19:178:25 | "key17" | semmle.label | "key17" |
|
||||
| main.go:179:51:179:56 | secret | semmle.label | secret |
|
||||
| main.go:184:12:184:26 | type conversion | semmle.label | type conversion |
|
||||
| main.go:184:19:184:25 | "key18" | semmle.label | "key18" |
|
||||
| main.go:185:42:185:47 | secret | semmle.label | secret |
|
||||
| main.go:190:12:190:26 | type conversion | semmle.label | type conversion |
|
||||
| main.go:190:19:190:25 | "key19" | semmle.label | "key19" |
|
||||
| main.go:193:33:193:38 | secret | semmle.label | secret |
|
||||
| sanitizer.go:17:9:17:21 | type conversion | semmle.label | type conversion |
|
||||
| sanitizer.go:17:16:17:20 | `key` | semmle.label | `key` |
|
||||
| sanitizer.go:18:44:18:46 | key | semmle.label | key |
|
||||
subpaths
|
||||
#select
|
||||
| HardcodedKeysBad.go:19:28:19:39 | mySigningKey | HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" | HardcodedKeysBad.go:19:28:19:39 | mySigningKey | $@ is used to sign a JWT token. | HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" | Hardcoded String |
|
||||
| main.go:42:28:42:39 | mySigningKey | main.go:33:25:33:30 | "key1" | main.go:42:28:42:39 | mySigningKey | $@ is used to sign a JWT token. | main.go:33:25:33:30 | "key1" | Hardcoded String |
|
||||
| main.go:50:16:50:29 | type conversion | main.go:50:23:50:28 | "key2" | main.go:50:16:50:29 | type conversion | $@ is used to sign a JWT token. | main.go:50:23:50:28 | "key2" | Hardcoded String |
|
||||
| main.go:69:44:69:46 | key | main.go:68:16:68:21 | `key3` | main.go:69:44:69:46 | key | $@ is used to sign a JWT token. | main.go:68:16:68:21 | `key3` | Hardcoded String |
|
||||
| main.go:74:66:74:68 | key | main.go:73:16:73:21 | "key4" | main.go:74:66:74:68 | key | $@ is used to sign a JWT token. | main.go:73:16:73:21 | "key4" | Hardcoded String |
|
||||
| main.go:82:15:82:18 | key2 | main.go:77:17:77:22 | "key5" | main.go:82:15:82:18 | key2 | $@ is used to sign a JWT token. | main.go:77:17:77:22 | "key5" | Hardcoded String |
|
||||
| main.go:92:41:92:43 | key | main.go:88:16:88:21 | "key6" | main.go:92:41:92:43 | key | $@ is used to sign a JWT token. | main.go:88:16:88:21 | "key6" | Hardcoded String |
|
||||
| main.go:99:66:99:69 | key2 | main.go:97:17:97:22 | "key7" | main.go:99:66:99:69 | key2 | $@ is used to sign a JWT token. | main.go:97:17:97:22 | "key7" | Hardcoded String |
|
||||
| main.go:110:30:110:32 | key | main.go:105:16:105:21 | "key8" | main.go:110:30:110:32 | key | $@ is used to sign a JWT token. | main.go:105:16:105:21 | "key8" | Hardcoded String |
|
||||
| main.go:115:16:115:24 | sharedKey | main.go:114:22:114:27 | "key9" | main.go:115:16:115:24 | sharedKey | $@ is used to sign a JWT token. | main.go:114:22:114:27 | "key9" | Hardcoded String |
|
||||
| main.go:121:16:121:30 | sharedKeyglobal | main.go:118:30:118:36 | "key10" | main.go:121:16:121:30 | sharedKeyglobal | $@ is used to sign a JWT token. | main.go:118:30:118:36 | "key10" | Hardcoded String |
|
||||
| main.go:127:20:127:34 | type conversion | main.go:127:27:127:33 | "key11" | main.go:127:20:127:34 | type conversion | $@ is used to sign a JWT token. | main.go:127:27:127:33 | "key11" | Hardcoded String |
|
||||
| main.go:144:39:144:46 | mySecret | main.go:142:21:142:27 | "key12" | main.go:144:39:144:46 | mySecret | $@ is used to sign a JWT token. | main.go:142:21:142:27 | "key12" | Hardcoded String |
|
||||
| main.go:153:11:153:18 | mySecret | main.go:149:21:149:27 | "key13" | main.go:153:11:153:18 | mySecret | $@ is used to sign a JWT token. | main.go:149:21:149:27 | "key13" | Hardcoded String |
|
||||
| main.go:161:34:161:39 | secret | main.go:160:19:160:25 | "key14" | main.go:161:34:161:39 | secret | $@ is used to sign a JWT token. | main.go:160:19:160:25 | "key14" | Hardcoded String |
|
||||
| main.go:167:32:167:37 | secret | main.go:166:19:166:25 | "key15" | main.go:167:32:167:37 | secret | $@ is used to sign a JWT token. | main.go:166:19:166:25 | "key15" | Hardcoded String |
|
||||
| main.go:173:41:173:46 | secret | main.go:172:19:172:25 | "key16" | main.go:173:41:173:46 | secret | $@ is used to sign a JWT token. | main.go:172:19:172:25 | "key16" | Hardcoded String |
|
||||
| main.go:179:51:179:56 | secret | main.go:178:19:178:25 | "key17" | main.go:179:51:179:56 | secret | $@ is used to sign a JWT token. | main.go:178:19:178:25 | "key17" | Hardcoded String |
|
||||
| main.go:185:42:185:47 | secret | main.go:184:19:184:25 | "key18" | main.go:185:42:185:47 | secret | $@ is used to sign a JWT token. | main.go:184:19:184:25 | "key18" | Hardcoded String |
|
||||
| main.go:193:33:193:38 | secret | main.go:190:19:190:25 | "key19" | main.go:193:33:193:38 | secret | $@ is used to sign a JWT token. | main.go:190:19:190:25 | "key19" | Hardcoded String |
|
||||
| sanitizer.go:18:44:18:46 | key | sanitizer.go:17:16:17:20 | `key` | sanitizer.go:18:44:18:46 | key | $@ is used to sign a JWT token. | sanitizer.go:17:16:17:20 | `key` | Hardcoded String |
|
||||
@@ -1 +0,0 @@
|
||||
experimental/CWE-321/HardcodedKeys.ql
|
||||
@@ -1,7 +1,28 @@
|
||||
| AlertSuppressionExample.go:11:14:11:40 | "horsebatterystaplecorrect" | Hard-coded $@. | AlertSuppressionExample.go:11:14:11:40 | "horsebatterystaplecorrect" | password |
|
||||
| HardcodedCredentials.go:10:13:10:28 | "s3cretp4ssword" | Hard-coded $@. | HardcodedCredentials.go:10:13:10:28 | "s3cretp4ssword" | password |
|
||||
| HardcodedKeysBad.go:19:28:19:39 | mySigningKey | Hard-coded credential. | HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" | password |
|
||||
| jwt.go:42:28:42:39 | mySigningKey | Hard-coded credential. | jwt.go:33:25:33:30 | "key1" | password |
|
||||
| jwt.go:49:16:49:29 | type conversion | Hard-coded credential. | jwt.go:49:23:49:28 | "key2" | password |
|
||||
| jwt.go:68:44:68:46 | key | Hard-coded credential. | jwt.go:67:16:67:21 | `key3` | password |
|
||||
| jwt.go:73:66:73:68 | key | Hard-coded credential. | jwt.go:72:16:72:21 | "key4" | password |
|
||||
| jwt.go:81:15:81:18 | key2 | Hard-coded credential. | jwt.go:76:17:76:22 | "key5" | password |
|
||||
| jwt.go:91:41:91:43 | key | Hard-coded credential. | jwt.go:87:16:87:21 | "key6" | password |
|
||||
| jwt.go:98:66:98:69 | key2 | Hard-coded credential. | jwt.go:96:17:96:22 | "key7" | password |
|
||||
| jwt.go:109:30:109:32 | key | Hard-coded credential. | jwt.go:104:16:104:21 | "key8" | password |
|
||||
| jwt.go:114:16:114:24 | sharedKey | Hard-coded credential. | jwt.go:113:22:113:27 | "key9" | password |
|
||||
| jwt.go:120:16:120:30 | sharedKeyglobal | Hard-coded credential. | jwt.go:117:30:117:36 | "key10" | password |
|
||||
| jwt.go:126:20:126:34 | type conversion | Hard-coded credential. | jwt.go:126:27:126:33 | "key11" | password |
|
||||
| jwt.go:143:39:143:46 | safeName | Hard-coded credential. | jwt.go:141:21:141:27 | "key12" | password |
|
||||
| jwt.go:152:11:152:18 | safeName | Hard-coded credential. | jwt.go:148:21:148:27 | "key13" | password |
|
||||
| jwt.go:160:34:160:41 | safeName | Hard-coded credential. | jwt.go:159:21:159:27 | "key14" | password |
|
||||
| jwt.go:166:32:166:39 | safeName | Hard-coded credential. | jwt.go:165:21:165:27 | "key15" | password |
|
||||
| jwt.go:172:41:172:48 | safeName | Hard-coded credential. | jwt.go:171:21:171:27 | "key16" | password |
|
||||
| jwt.go:178:51:178:58 | safeName | Hard-coded credential. | jwt.go:177:21:177:27 | "key17" | password |
|
||||
| jwt.go:184:42:184:49 | safeName | Hard-coded credential. | jwt.go:183:21:183:27 | "key18" | password |
|
||||
| jwt.go:192:33:192:40 | safeName | Hard-coded credential. | jwt.go:189:21:189:27 | "key19" | password |
|
||||
| main.go:6:14:6:23 | "p4ssw0rd" | Hard-coded $@. | main.go:6:14:6:23 | "p4ssw0rd" | password |
|
||||
| main.go:12:1:26:30 | `-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQC/tzdtXKXcX6F3v3hR6+uYyZpIeXhhLflJkY2eILLQfAnwKlT5\nxIHW5QZcHQV9sCyZ8qSdPGif7PwgMbButMbByiZhCSugUFb6vjVqoktmslYF4LKH\niDgvmlwuJW0TvynxBLzDCwrRP+gpRT8wuAortWAx/03POTw7Mzi2cIPNsQIDAQAB\nAoGAMHCrqY9CPTdQhgAz94cDpTwzJmLCvtMt7J/BR5X9eF4O6MbZZ652HAUMIVQX\n4hUUf+VmIHB2AwqO/ddwO9ijaz04BslOSy/iYevHGlH65q4587NSlFWjvILMIQCM\nGBjfzJIxlLHVhjc2cFnyAE5YWjF/OMnJN0OhP9pxmCP/iM0CQQDxmQndQLdnV7+6\n8SvBHE8bg1LE8/BzTt68U3aWwiBjrHMFgzr//7Za4VF7h4ilFgmbh0F3sYz+C8iO\n0JrBRPeLAkEAyyTwnv/pgqTS/wuxIHUxRBpbdk3YvILAthNrGQg5uzA7eSeFu7Mv\nGtEkXsaqCDbdehgarFfNN8PB6OMRIbsXMwJBAOjhH8UJ0L/osYO9XPO0GfznRS1c\nBnbfm4vk1/bSAO6TF/xEVubU0i4f6q8sIecfqvskEVMS7lkjeptPMR0DIakCQE+7\nuQH/Wizf+r0GXshplyOu4LVHisk63N7aMlAJ7XbuUHmWLKRmiReSfR8CBNzig/2X\nFmkMsUyw9hwte5zsrQcCQQCrOkZvzUj9j1HKG+32EJ2E4kisJZmAgF9GI+z6oxpi\nExped5tp8EWytCjRwKhOcc0068SgaqhKvyyUWpbx32VQ\n-----END RSA PRIVATE KEY-----` | Hard-coded private key. | main.go:12:1:26:30 | `-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQC/tzdtXKXcX6F3v3hR6+uYyZpIeXhhLflJkY2eILLQfAnwKlT5\nxIHW5QZcHQV9sCyZ8qSdPGif7PwgMbButMbByiZhCSugUFb6vjVqoktmslYF4LKH\niDgvmlwuJW0TvynxBLzDCwrRP+gpRT8wuAortWAx/03POTw7Mzi2cIPNsQIDAQAB\nAoGAMHCrqY9CPTdQhgAz94cDpTwzJmLCvtMt7J/BR5X9eF4O6MbZZ652HAUMIVQX\n4hUUf+VmIHB2AwqO/ddwO9ijaz04BslOSy/iYevHGlH65q4587NSlFWjvILMIQCM\nGBjfzJIxlLHVhjc2cFnyAE5YWjF/OMnJN0OhP9pxmCP/iM0CQQDxmQndQLdnV7+6\n8SvBHE8bg1LE8/BzTt68U3aWwiBjrHMFgzr//7Za4VF7h4ilFgmbh0F3sYz+C8iO\n0JrBRPeLAkEAyyTwnv/pgqTS/wuxIHUxRBpbdk3YvILAthNrGQg5uzA7eSeFu7Mv\nGtEkXsaqCDbdehgarFfNN8PB6OMRIbsXMwJBAOjhH8UJ0L/osYO9XPO0GfznRS1c\nBnbfm4vk1/bSAO6TF/xEVubU0i4f6q8sIecfqvskEVMS7lkjeptPMR0DIakCQE+7\nuQH/Wizf+r0GXshplyOu4LVHisk63N7aMlAJ7XbuUHmWLKRmiReSfR8CBNzig/2X\nFmkMsUyw9hwte5zsrQcCQQCrOkZvzUj9j1HKG+32EJ2E4kisJZmAgF9GI+z6oxpi\nExped5tp8EWytCjRwKhOcc0068SgaqhKvyyUWpbx32VQ\n-----END RSA PRIVATE KEY-----` | certificate |
|
||||
| main.go:44:14:44:19 | "p4ss" | Hard-coded $@. | main.go:44:14:44:19 | "p4ss" | password |
|
||||
| main.go:48:13:48:15 | tmp | Hard-coded $@. | main.go:44:14:44:19 | "p4ss" | password |
|
||||
| main.go:50:15:50:21 | "p4ss2" | Hard-coded $@. | main.go:50:15:50:21 | "p4ss2" | password |
|
||||
| sanitizer.go:18:44:18:46 | key | Hard-coded credential. | sanitizer.go:17:16:17:20 | `key` | password |
|
||||
|
||||
@@ -44,7 +44,6 @@ func gjwtt() (interface{}, error) {
|
||||
|
||||
func gin_jwt() (interface{}, error) {
|
||||
var identityKey = "id"
|
||||
// authMiddleware, err :=
|
||||
return jwt.New(&jwt.GinJWTMiddleware{
|
||||
Realm: "test zone",
|
||||
Key: []byte("key2"), // BAD
|
||||
@@ -124,7 +123,7 @@ func lejwt2() (interface{}, error) {
|
||||
func gogfjwt() interface{} {
|
||||
return &gogf.GfJWTMiddleware{
|
||||
Realm: "test zone",
|
||||
Key: []byte("key11"),
|
||||
Key: []byte("key11"), // BAD
|
||||
Timeout: time.Minute * 5,
|
||||
MaxRefresh: time.Minute * 5,
|
||||
IdentityKey: "id",
|
||||
@@ -139,58 +138,58 @@ func gogfjwt() interface{} {
|
||||
}
|
||||
|
||||
func irisjwt() interface{} {
|
||||
mySecret := []byte("key12")
|
||||
safeName := []byte("key12")
|
||||
token := iris.NewTokenWithClaims(nil, nil)
|
||||
tokenString, _ := token.SignedString(mySecret)
|
||||
tokenString, _ := token.SignedString(safeName) // BAD
|
||||
return tokenString
|
||||
}
|
||||
|
||||
func iris12jwt2() interface{} {
|
||||
mySecret := []byte("key13")
|
||||
safeName := []byte("key13")
|
||||
|
||||
s := &iris12.Signer{
|
||||
Alg: nil,
|
||||
Key: mySecret,
|
||||
Key: safeName, // BAD
|
||||
MaxAge: 3 * time.Second,
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func irisjwt3() interface{} {
|
||||
secret := []byte("key14")
|
||||
signer := iris12.NewSigner(nil, secret, 3*time.Second)
|
||||
safeName := []byte("key14")
|
||||
signer := iris12.NewSigner(nil, safeName, 3*time.Second) // BAD
|
||||
return signer
|
||||
}
|
||||
|
||||
func katarasJwt() interface{} {
|
||||
secret := []byte("key15")
|
||||
token, _ := kataras.Sign(nil, secret, nil, nil)
|
||||
safeName := []byte("key15")
|
||||
token, _ := kataras.Sign(nil, safeName, nil, nil) // BAD
|
||||
return token
|
||||
}
|
||||
|
||||
func katarasJwt2() interface{} {
|
||||
secret := []byte("key16")
|
||||
token, _ := kataras.SignEncrypted(nil, secret, nil, nil)
|
||||
safeName := []byte("key16")
|
||||
token, _ := kataras.SignEncrypted(nil, safeName, nil, nil) // BAD
|
||||
return token
|
||||
}
|
||||
|
||||
func katarasJwt3() interface{} {
|
||||
secret := []byte("key17")
|
||||
token, _ := kataras.SignEncryptedWithHeader(nil, secret, nil, nil, nil)
|
||||
safeName := []byte("key17")
|
||||
token, _ := kataras.SignEncryptedWithHeader(nil, safeName, nil, nil, nil) // BAD
|
||||
return token
|
||||
}
|
||||
|
||||
func katarasJwt4() interface{} {
|
||||
secret := []byte("key18")
|
||||
token, _ := kataras.SignWithHeader(nil, secret, nil, nil)
|
||||
safeName := []byte("key18")
|
||||
token, _ := kataras.SignWithHeader(nil, safeName, nil, nil) // BAD
|
||||
return token
|
||||
}
|
||||
|
||||
func katarasJwt5() {
|
||||
secret := []byte("key19")
|
||||
safeName := []byte("key19")
|
||||
var keys kataras.Keys
|
||||
var alg kataras.Alg
|
||||
keys.Register(alg, "api", nil, secret)
|
||||
keys.Register(alg, "api", nil, safeName) // BAD
|
||||
}
|
||||
|
||||
func main() {
|
||||
Reference in New Issue
Block a user