Explorar el Código

feat(jwt): detect base64-encoded tokens (#1256)

Richard Gomez hace 2 años
padre
commit
ed34259e9c
Se han modificado 3 ficheros con 136 adiciones y 0 borrados
  1. 1 0
      cmd/generate/config/main.go
  2. 127 0
      cmd/generate/config/rules/jwt.go
  3. 8 0
      config/gitleaks.toml

+ 1 - 0
cmd/generate/config/main.go

@@ -95,6 +95,7 @@ func main() {
 	configRules = append(configRules, rules.JFrogAPIKey())
 	configRules = append(configRules, rules.JFrogIdentityToken())
 	configRules = append(configRules, rules.JWT())
+	configRules = append(configRules, rules.JWTBase64())
 	configRules = append(configRules, rules.KrakenAccessToken())
 	configRules = append(configRules, rules.KucoinAccessToken())
 	configRules = append(configRules, rules.KucoinSecretKey())

+ 127 - 0
cmd/generate/config/rules/jwt.go

@@ -1,6 +1,10 @@
 package rules
 
 import (
+	b64 "encoding/base64"
+	"fmt"
+	"regexp"
+
 	"github.com/zricethezav/gitleaks/v8/config"
 )
 
@@ -59,3 +63,126 @@ func JWT() *config.Rule {
 	fps := []string{}
 	return validate(r, tps, fps)
 }
+
+func JWTBase64() *config.Rule {
+	// define rule
+	r := config.Rule{
+		RuleID:      "jwt-base64",
+		Description: "Base64-encoded JSON Web Token",
+		Regex: regexp.MustCompile(
+			`\bZXlK(?:(?P<alg>aGJHY2lPaU)|(?P<apu>aGNIVWlPaU)|(?P<apv>aGNIWWlPaU)|(?P<aud>aGRXUWlPaU)|(?P<b64>aU5qUWlP)|(?P<crit>amNtbDBJanBi)|(?P<cty>amRIa2lPaU)|(?P<epk>bGNHc2lPbn)|(?P<enc>bGJtTWlPaU)|(?P<jku>cWEzVWlPaU)|(?P<jwk>cWQyc2lPb)|(?P<iss>cGMzTWlPaU)|(?P<iv>cGRpSTZJ)|(?P<kid>cmFXUWlP)|(?P<key_ops>clpYbGZiM0J6SWpwY)|(?P<kty>cmRIa2lPaUp)|(?P<nonce>dWIyNWpaU0k2)|(?P<p2c>d01tTWlP)|(?P<p2s>d01uTWlPaU)|(?P<ppt>d2NIUWlPaU)|(?P<sub>emRXSWlPaU)|(?P<svt>emRuUWlP)|(?P<tag>MFlXY2lPaU)|(?P<typ>MGVYQWlPaUp)|(?P<url>MWNtd2l)|(?P<use>MWMyVWlPaUp)|(?P<ver>MlpYSWlPaU)|(?P<version>MlpYSnphVzl1SWpv)|(?P<x>NElqb2)|(?P<x5c>NE5XTWlP)|(?P<x5t>NE5YUWlPaU)|(?P<x5ts256>NE5YUWpVekkxTmlJNkl)|(?P<x5u>NE5YVWlPaU)|(?P<zip>NmFYQWlPaU))[a-zA-Z0-9\/\\_+\-\r\n]{40,}={0,2}`),
+		Keywords: []string{"zxlk"},
+	}
+
+	tps := generateTestValues()
+	fps := []string{
+		`-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG/MacGPG2 v2
+Comment: GPGTools - https://gpgtools.org
+
+mQENBFOrMNcBCAC+gLI4s3bUkobS5NpOQbWfjWXbqC0Ixpc5bZYDOvsmfstmswna
+UWUXkRH9RONabzrAu4TGvW0f5DkC2fuWWHJhZWEccn+VE83+avMZN4/mzldSXPNX
+A6F7+wHb1DjG+FCDcxMghkwDjGc16LOtZGufUo5iRQaC5pmNBOgDWdiObGPKOTEL
+/uU8zLtKi2cibbkhRm22IGOzGyZMZN6zvEtPzlCp3eZEGMW0Ig+kbl6SaSDrSJNK
+wElYcr/kJ9QF6CQ2iwZCGeL2jH5QaOi5uj1LXONpCd9nPeyDXc+Z20gXZiqkwRLc
+IBPKza6hq/+4nwHBq8DNLv0W4xNC59jLbIhpABEBAAG0LEZyYW5rIE5vdGhhZnQg
+PGZub3RoYWZ0QGFsdW1uaS5zdGFuZm9yZC5lZHU+iQE9BBMBCgAnBQJTqzDXAhsD
+BQkHhh+ABQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJECqYOYG1w7FJOr4IAK8x
+ec4jbjd6jkKe0YJGdPzg6TM73ISV5VrUlJX7O3jgxHB4M8KIHN/8A/+ZxLk7WM96
+iq0C8atWHkCkQBtNduWhzAFccQlpxrrb18T5/oItcrmX9Dx2H5WeIl4WAoqe0MTk
+iMPv29RMMH9RJvXL0ihuuH4Z0VxV5nurI9QmGzG69QOzfP9qY1EfQEceO7OqXXvY
+vvBEUbmWshLuHJ6tOQY5ib3+aLO7m+yJTgJ7s6DHBDqLhqJPW0g7jiJcrDhYXsoS
+JMMhMdUhckeZfTXm1N3Dc+/t9/E8NZjdZ2q/ZZzvygC4mu0uihwBKFqoFvXCHRaW
+Rf4uYxE+/Upna/mbXQi5AQ0EU6sw1wEIALSp9Cc4t/F2k+rwEfEMXihXLcLM9Dmh
+ukz++kMSCSuq4QHE+I4rLda/lVSNJCXaXrGVkzJuzmpEeQFdhr6nLW9ZYhzK8FIc
+YyfsYTQxXUVf5W4e/XfKNoG9lrwQd5XHxJTBJ57XjjoWJYPQ69NWH8622foOBpux
+xewgR2LEFgl+ksu7aQL4cQif6D3dko3EiIf1t0LDBXxFEREFCg+vkDFsDIW5bdaI
+mDYwewGj7dAPLuo0sx1We+uBxb+j30xw/ASDOBhO3ratQWs+4w2FC7gw7cuf0CJC
+/hMEw8nloGsIbqBmAnLdlQBxkfFG9DqRBNdSUM8xI66F0eGaaPHJ/S8AEQEAAYkB
+JQQYAQoADwUCU6sw1wIbDAUJB4YfgAAKCRAqmDmBtcOxSZvvB/4w6S5YZQUmDVYK
+9HPOm49qWxGPd5dLHr2g388sJ4LDK98Q9oicHgf2R35OXTyqhv4kFJL3eukQ6oLW
+QOqQKLRycrQUu7eSESAiVmJ1gbuXLAWJmvUABGSYzj3BjWQRexYW/MZ51XqNftF9
+oOSAoFWrdqeJbHoxPTXIb6P8EWk4Ei2j2bSIfBBSbBMSB6Kfk9IjpISM8+97RS5o
+6605rmM5MY1Lz8cq8AZIYJs/MnUCZrpQ0c9QSWrflHAeWAy6xMGfdSynbEExQ4z8
+AIfKWMro74nRFbAnv/BzrF2R8uHmdE7T6q9ZZsAydlaxQbdmyhCeGAdw93CwAypb
+vHVobJ8A
+=mIC1
+-----END PGP PUBLIC KEY BLOCK-----`,
+	}
+	return validate(r, tps, fps)
+}
+
+func generateTestValues() []string {
+	// Sample JWT from RFC-7519
+	jwtSuffix := ".eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
+	// Validate known header parameters
+	// https://www.iana.org/assignments/jose/jose.xhtml
+	headers := map[string][]string{
+		"alg": {
+			`"ES256"`,
+			`"ES384"`,
+			`"ES512"`,
+			`"ECDH-ES"`,
+			`"HS256"`,
+			`"HS384"`,
+			`"HS512"`,
+			`"RS256"`,
+			`"RS384"`,
+			`"RS512"`,
+			`"PS256"`,
+			`"PS384"`, `"PS512"`,
+			`"none"`,
+			// Nonstandard
+			`"A128KW"`,
+			`"ECDH-ES+A256KW"`,
+			`"RSA-OAEP"`,
+		},
+		"apu":     {`"Tx9qG69ZfodhRos-8qfhTPc6ZFnNUcgNDVdHqX1UR3s"`, `"RfXdxTfIzilWBzWWX3ovHBDzgDcLNy0BFJWSxa0dqnw"`},
+		"apv":     {`"ZGlkOmVsZW06cm9wc3RlbjpFa"`, `"ZGlkOmtleTp6Nk1rak1TWWF1dU1neDlhekV5VW5UVzVvNWpGUmtiQnU1VDgzZjM5dU53bnNHbW0jejZMU29HdFpTclVNWnVkQWFnekVmWWY3azhqSFpjR0Q3OVNveDd2NHdDa0RLTlN3"`},
+		"aud":     {`"https://vault.example.com"`, `"http://example.com"`},
+		"b64":     {`true`, `false`},
+		"crit":    {`["exp"]`},
+		"cty":     {`"example"`, `"json"`},
+		"epk":     {`{"crv":"X25519","kty":"OKP","x":"Tx9qG69ZfodhRos-8qfhTPc6ZFnNUcgNDVdHqX1UR3s"}`, `{"kty":"OKP","crv":"X25519","x":"RfXdxTfIzilWBzWWX3ovHBDzgDcLNy0BFJWSxa0dqnw"}`},
+		"enc":     {`"A256GCM"`, `"A256CBC-HS512"`, `"A128CBC-HS256"`},
+		"jku":     {`"https://c2id.com/jwks.json"`},
+		"jwk":     {`{"crv":"P-256","kid":"DB2X:GSG2:72H3:AE3R:KCMI:Y77E:W7TF:ERHK:V5HR:JJ2Y:YMS6:HFGJ","kty":"EC","x":"jyr9-xZBorSC9fhqNsmfU_Ud31wbaZ-bVGz0HmySvbQ","y":"vkE6qZCCvYRWjSUwgAOvibQx_s8FipYkAiHS0VnAFNs"}`, `{"kty":"RSA","n":"jyTwiSJACtW_SW-aiihQS5Y5QR704zUwjhlevY0oK-y5wP7SlIc2hq2OPVRarCzjhOxZl2AQFzM5VCR7xRDcnIn9t_pl7Mgsnx9hKDS9yQ24YXzhQ4cMEVVuqwcHvXqPdWDSoCZ1ccMqiiPyBSNGQTXMPY5PBxMOR47XwOb4eNMOPqnzVio3MEtL2wphtEonP3MY6pxJJzzel04wSCRZ4n06reqwER3KwRFPnRpRxAgmSEot5IBLIT3jj-amT5sD7YoUDbPmLk23zgDBIhX88fkClilg1W-fUi1XxYZomEPGvV7OrE1yszt4YDPqKgjJT8t2JPy__1ri-8rZgSxn5Q","e":"AQAB"`},
+		"iss":     {`"http://localhost:8087/realms/grafana"`, `"kubernetes/serviceaccount"`},
+		"iv":      {`"zjJPRrj0TGez9JYkChTrB3iqKoDkiBhn"`, `"10PlAIteHLVABtt"`},
+		"kid":     {`"my_key_id"`, `"did:example:123#zC1Rnuvw9rVa6E5TKF4uQVRuQuaCpVgB81Um2u17Fu7UK"`},
+		"key_ops": {`["sign"]`, `["decrypt"]`, `["encrypt"]`},
+		"kty":     {`"EC"`, `"RSA"`},
+		"nonce":   {`"Os_sBjfWzVZenwwjvLrwXA"`, `"LDDZAGcBuKYpuNlFTCxPYw"`},
+		"p2c":     {`4096`, `1000`},
+		"p2s":     {`"c_ORk4HSsqZD2LvVeCUHqg"`},
+		"ppt":     {`"foo"`},
+		"sub":     {`"project_path:my-group/my-project:ref_type:branch:ref:feature-branch-1"`, `"1234567890"`},
+		// I cannot find any real-world examples of the svt header
+		// and the RFC doesn't seem to explicitly state the content.
+		"svt":      {``},
+		"tag":      {`"h6mJqHn33oCsDd5X57MI-g"`},
+		"typ":      {`"JWT"`, `"JWK"`, `"JSOE"`, `"JSON"`, `"plain"`},
+		"url":      {`"https://example.com"`},
+		"use":      {`"enc"`, `"sig"`},
+		"ver":      {`"2"`, `"3"`},
+		"version":  {`"2"`, `"3"`},
+		"x5c":      {`["MIICmzCCAYMCBgF4HR7HNDANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjEwMzEwMTcwOTE5WhcNMzEwMzEwMTcxMDU5WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCpLzXHp8i09R2HU5YJPyncC4tiAWWmaDrVZenqynWlWKOjIXb0Y5JoP3ET68u16Bf7mHQGc/u9rRvCw4A92HpJ15WyUSJ80YcK0gPTE0Woc1ZxdK3h4t9AoA8VSrROwQ77w/VAdGrrJ4bwkAVrFqSRpqAsW5XxV3/bU8YkVaG8mh0kuFf/5ib0vxdSkg+mz+ZCuIxQ5YN77kNaMecO19XuaBo7FsG9WjfCPxXYuajkuLgdptPgwTN4np70h0WjaSP/jhjL2ixf48w+27wFDP+ic+B/TCOtVa3fj1GPo6RLxHGU0Zh64jFhmvRM6E/kX7IQ+FJcOwp1VPA9/vMABopAgMBAAEwDQYJKoZIhvcNAQELBQADggEBALILq1Z4oQNJZEUt24VZcvknsWtQtvPxl3JNcBQgDR5/IMgl5VndRZ9OT56KUqrR5xRsWiCvh5Lgv4fUEzAAo9ToiPLub1SKP063zWrvfgi3YZ19bty0iXFm7l2cpQ3ejFV7WpcdLJE0lapFdPLo6QaRdgNu/1p4vbYg7zSK1fQ0OY5b3ajhAx/bhWlrN685owRbO5/r4rUOa6oo9l4Qn7jUxKUx4rcoe7zUM7qrpOPqKvn0DBp3n1/+9pOZXCjIfZGvYwP5NhzBDCkRzaXcJHlOqWzMBzyovVrzVmUilBcj+EsTYJs0gVXKzduX5zO6YWhFs23lu7AijdkxTY65YM0="]`},
+		"x5t":      {`"IYIeevIT57t8ppUejM42Bqx6f3I"`},
+		"x5t#S256": {`"TuOrBy2NcTlFSWuZ8Kh8W8AjQagb4fnfP1SlKMO8-So"`},
+		"x5u":      {`"https://tel.example.org/passport.cer"`},
+		"zip":      {`"DEF"`},
+	}
+
+	var examples []string
+	for key, values := range headers {
+		for _, value := range values {
+			header := fmt.Sprintf(`{"%s":%s}`, key, value)
+			jwt := []byte(b64.RawURLEncoding.EncodeToString([]byte(header)) + jwtSuffix)
+			examples = append(examples, b64.StdEncoding.EncodeToString(jwt))
+			examples = append(examples, b64.RawStdEncoding.EncodeToString(jwt))
+			examples = append(examples, b64.URLEncoding.EncodeToString(jwt))
+			examples = append(examples, b64.RawURLEncoding.EncodeToString(jwt))
+		}
+	}
+	return examples
+}

+ 8 - 0
config/gitleaks.toml

@@ -2180,6 +2180,14 @@ keywords = [
     "ey",
 ]
 
+[[rules]]
+id = "jwt-base64"
+description = "Base64-encoded JSON Web Token"
+regex = '''\bZXlK(?:(?P<alg>aGJHY2lPaU)|(?P<apu>aGNIVWlPaU)|(?P<apv>aGNIWWlPaU)|(?P<aud>aGRXUWlPaU)|(?P<b64>aU5qUWlP)|(?P<crit>amNtbDBJanBi)|(?P<cty>amRIa2lPaU)|(?P<epk>bGNHc2lPbn)|(?P<enc>bGJtTWlPaU)|(?P<jku>cWEzVWlPaU)|(?P<jwk>cWQyc2lPb)|(?P<iss>cGMzTWlPaU)|(?P<iv>cGRpSTZJ)|(?P<kid>cmFXUWlP)|(?P<key_ops>clpYbGZiM0J6SWpwY)|(?P<kty>cmRIa2lPaUp)|(?P<nonce>dWIyNWpaU0k2)|(?P<p2c>d01tTWlP)|(?P<p2s>d01uTWlPaU)|(?P<ppt>d2NIUWlPaU)|(?P<sub>emRXSWlPaU)|(?P<svt>emRuUWlP)|(?P<tag>MFlXY2lPaU)|(?P<typ>MGVYQWlPaUp)|(?P<url>MWNtd2l)|(?P<use>MWMyVWlPaUp)|(?P<ver>MlpYSWlPaU)|(?P<version>MlpYSnphVzl1SWpv)|(?P<x>NElqb2)|(?P<x5c>NE5XTWlP)|(?P<x5t>NE5YUWlPaU)|(?P<x5ts256>NE5YUWpVekkxTmlJNkl)|(?P<x5u>NE5YVWlPaU)|(?P<zip>NmFYQWlPaU))[a-zA-Z0-9\/\\_+\-\r\n]{40,}={0,2}'''
+keywords = [
+    "zxlk",
+]
+
 [[rules]]
 id = "kraken-access-token"
 description = "Kraken Access Token"