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

Commit

Permalink
Fix security issue with aud validation
Browse files Browse the repository at this point in the history
Aud validation on the JWT was being bypassed if a list of claims was presented
to the server. This commit checks if the aud claim is a list of strings, if not
it checks if its a single string, if not it will return invalid

Signed-off-by: Alistair Hey <alistair.hey@form3.tech>
  • Loading branch information
ah-f3 committed Sep 15, 2020
1 parent dc14462 commit 6474ec9
Show file tree
Hide file tree
Showing 4 changed files with 90 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
10 changes: 9 additions & 1 deletion map_claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,15 @@ 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, ok := m["aud"].([]string)
if !ok {
strAud, ok := m["aud"].(string)
if !ok {
return false
}
aud = append(aud, strAud)
}

return verifyAud(aud, cmp, req)
}

Expand Down
71 changes: 71 additions & 0 deletions map_claims_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
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{
}
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 6474ec9

Please sign in to comment.