Skip to content
This repository has been archived by the owner on May 21, 2022. It is now read-only.

Commit

Permalink
Fix sec vuln with list of claims
Browse files Browse the repository at this point in the history
Signed-off-by: Alistair Hey <alistair@heyal.co.uk>
  • Loading branch information
Waterdrips committed Sep 14, 2020
1 parent dc14462 commit 63de7be
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.DS_Store
bin
.idea/


16 changes: 9 additions & 7 deletions claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type Claims interface {
// https://tools.ietf.org/html/rfc7519#section-4.1
// See examples for how to use this with your own claim types
type StandardClaims struct {
Audience string `json:"aud,omitempty"`
Audience []string `json:"aud,omitempty"`
ExpiresAt int64 `json:"exp,omitempty"`
Id string `json:"jti,omitempty"`
IssuedAt int64 `json:"iat,omitempty"`
Expand Down Expand Up @@ -90,15 +90,17 @@ func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {

// ----- helpers

func verifyAud(aud string, cmp string, required bool) bool {
if aud == "" {
func verifyAud(aud []string, cmp string, required bool) bool {
if len(aud) == 0 {
return !required
}
if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 {
return true
} else {
return false

for _, a := range aud {
if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 {
return true
}
}
return false
}

func verifyExp(exp int64, now int64, required bool) bool {
Expand Down
8 changes: 7 additions & 1 deletion map_claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ type MapClaims map[string]interface{}
// Compares the aud claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
aud, _ := m["aud"].(string)
aud, _ := m["aud"].([]string)

// special case where aud is a single string not list of strings
if aud == nil {
strAud, _ := m["aud"].(string)
aud = append(aud, strAud)
}
return verifyAud(aud, cmp, req)
}

Expand Down
72 changes: 72 additions & 0 deletions map_claims_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package jwt

import "testing"

func Test_mapClaims_list_aud(t *testing.T){
mapClaims := MapClaims{
"aud": []string{"foo"},
}
want := true
got := mapClaims.VerifyAudience("foo", true)

if want != got {
t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got)
}
}
func Test_mapClaims_string_aud(t *testing.T){
mapClaims := MapClaims{
"aud": "foo",
}
want := true
got := mapClaims.VerifyAudience("foo", true)

if want != got {
t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got)
}
}

func Test_mapClaims_list_aud_no_match(t *testing.T){
mapClaims := MapClaims{
"aud": []string{"bar"},
}
want := false
got := mapClaims.VerifyAudience("foo", true)

if want != got {
t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got)
}
}
func Test_mapClaims_string_aud_fail(t *testing.T){
mapClaims := MapClaims{
"aud": "bar",
}
want := false
got := mapClaims.VerifyAudience("foo", true)

if want != got {
t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got)
}
}

func Test_mapClaims_string_aud_no_claim(t *testing.T){
mapClaims := MapClaims{
}
want := false
got := mapClaims.VerifyAudience("foo", true)

if want != got {
t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got)
}
}

func Test_mapClaims_string_aud_no_claim_not_required(t *testing.T){
mapClaims := MapClaims{
//"aud": "",
}
want := false
got := mapClaims.VerifyAudience("foo", false)

if want != got {
t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got)
}
}

0 comments on commit 63de7be

Please sign in to comment.