diff --git a/internal/auth/bearer.go b/internal/auth/bearer.go index eac7e8d..0b2b3c5 100644 --- a/internal/auth/bearer.go +++ b/internal/auth/bearer.go @@ -43,6 +43,10 @@ func (ss *BearerSecurityScheme) GetCookies() []*http.Cookie { return []*http.Cookie{} } +func (ss *BearerSecurityScheme) HasValidValue() bool { + return ss.ValidValue != nil +} + func (ss *BearerSecurityScheme) GetValidValue() interface{} { return *ss.ValidValue } diff --git a/internal/auth/bearer_test.go b/internal/auth/bearer_test.go index bdb9b1f..f780526 100644 --- a/internal/auth/bearer_test.go +++ b/internal/auth/bearer_test.go @@ -48,6 +48,25 @@ func TestBearerSecurityScheme_GetCookies(t *testing.T) { assert.Empty(t, cookies) } +func TestBearerSecurityScheme_HasValidValue(t *testing.T) { + name := "token" + value := "abc123" + ss := auth.NewAuthorizationBearerSecurityScheme(name, &value) + + result := ss.HasValidValue() + + assert.True(t, result) +} + +func TestBearerSecurityScheme_HasValidValueFalse(t *testing.T) { + name := "token" + ss := auth.NewAuthorizationBearerSecurityScheme(name, nil) + + result := ss.HasValidValue() + + assert.False(t, result) +} + func TestBearerSecurityScheme_GetValidValue(t *testing.T) { name := "token" value := "abc123" diff --git a/internal/auth/jwt_bearer.go b/internal/auth/jwt_bearer.go index 1ae40cc..cce2703 100644 --- a/internal/auth/jwt_bearer.go +++ b/internal/auth/jwt_bearer.go @@ -56,6 +56,10 @@ func (ss *JWTBearerSecurityScheme) GetCookies() []*http.Cookie { return []*http.Cookie{} } +func (ss *JWTBearerSecurityScheme) HasValidValue() bool { + return ss.ValidValue != nil +} + func (ss *JWTBearerSecurityScheme) GetValidValue() interface{} { return *ss.ValidValue } diff --git a/internal/auth/jwt_bearer_test.go b/internal/auth/jwt_bearer_test.go index a300e2b..4a1393f 100644 --- a/internal/auth/jwt_bearer_test.go +++ b/internal/auth/jwt_bearer_test.go @@ -5,14 +5,13 @@ import ( "testing" "github.com/cerberauth/vulnapi/internal/auth" + "github.com/cerberauth/vulnapi/jwt" "github.com/stretchr/testify/assert" ) -const fakeJWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U" - func TestNewAuthorizationJWTBearerSecurityScheme(t *testing.T) { name := "token" - value := fakeJWT + value := jwt.FakeJWT ss, err := auth.NewAuthorizationJWTBearerSecurityScheme(name, &value) assert.NoError(t, err) @@ -34,7 +33,7 @@ func TestNewAuthorizationJWTBearerSecuritySchemeWithInvalidJWT(t *testing.T) { func TestJWTBearerSecurityScheme_GetHeaders(t *testing.T) { name := "token" - value := fakeJWT + value := jwt.FakeJWT attackValue := "xyz789" ss, err := auth.NewAuthorizationJWTBearerSecurityScheme(name, &value) ss.SetAttackValue(attackValue) @@ -49,7 +48,7 @@ func TestJWTBearerSecurityScheme_GetHeaders(t *testing.T) { func TestJWTBearerSecurityScheme_GetCookies(t *testing.T) { name := "token" - value := fakeJWT + value := jwt.FakeJWT ss, err := auth.NewAuthorizationJWTBearerSecurityScheme(name, &value) cookies := ss.GetCookies() @@ -57,9 +56,28 @@ func TestJWTBearerSecurityScheme_GetCookies(t *testing.T) { assert.Empty(t, cookies) } +func TestJWTBearerSecurityScheme_HasValidValue(t *testing.T) { + name := "token" + value := jwt.FakeJWT + ss, err := auth.NewAuthorizationJWTBearerSecurityScheme(name, &value) + hasValidValue := ss.HasValidValue() + + assert.NoError(t, err) + assert.True(t, hasValidValue) +} + +func TestJWTBearerSecurityScheme_HasValidValue_WhenNoValue(t *testing.T) { + name := "token" + ss, err := auth.NewAuthorizationJWTBearerSecurityScheme(name, nil) + hasValidValue := ss.HasValidValue() + + assert.NoError(t, err) + assert.False(t, hasValidValue) +} + func TestJWTBearerSecurityScheme_GetValidValue(t *testing.T) { name := "token" - value := fakeJWT + value := jwt.FakeJWT ss, err := auth.NewAuthorizationJWTBearerSecurityScheme(name, &value) validValue := ss.GetValidValue() @@ -69,7 +87,7 @@ func TestJWTBearerSecurityScheme_GetValidValue(t *testing.T) { func TestJWTBearerSecurityScheme_GetValidValueWriter(t *testing.T) { name := "token" - value := fakeJWT + value := jwt.FakeJWT ss, err := auth.NewAuthorizationJWTBearerSecurityScheme(name, &value) writer := ss.GetValidValueWriter() @@ -79,7 +97,7 @@ func TestJWTBearerSecurityScheme_GetValidValueWriter(t *testing.T) { func TestJWTBearerSecurityScheme_SetAttackValue(t *testing.T) { name := "token" - value := fakeJWT + value := jwt.FakeJWT ss, err := auth.NewAuthorizationJWTBearerSecurityScheme(name, &value) attackValue := "xyz789" ss.SetAttackValue(attackValue) @@ -90,7 +108,7 @@ func TestJWTBearerSecurityScheme_SetAttackValue(t *testing.T) { func TestJWTBearerSecurityScheme_GetAttackValue(t *testing.T) { name := "token" - value := fakeJWT + value := jwt.FakeJWT ss, err := auth.NewAuthorizationJWTBearerSecurityScheme(name, &value) attackValue := "xyz789" ss.SetAttackValue(attackValue) diff --git a/internal/auth/security_scheme.go b/internal/auth/security_scheme.go index f1fbccd..0b909cb 100644 --- a/internal/auth/security_scheme.go +++ b/internal/auth/security_scheme.go @@ -17,6 +17,7 @@ type SecurityScheme interface { GetHeaders() http.Header GetCookies() []*http.Cookie GetValidValue() interface{} + HasValidValue() bool GetValidValueWriter() interface{} SetAttackValue(v interface{}) GetAttackValue() interface{} @@ -38,6 +39,10 @@ func (ss *NoAuthSecurityScheme) GetCookies() []*http.Cookie { return []*http.Cookie{} } +func (ss *NoAuthSecurityScheme) HasValidValue() bool { + return false +} + func (ss *NoAuthSecurityScheme) GetValidValue() interface{} { return "" } diff --git a/jwt/const.go b/jwt/const.go new file mode 100644 index 0000000..02a5c2a --- /dev/null +++ b/jwt/const.go @@ -0,0 +1,3 @@ +package jwt + +const FakeJWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U" diff --git a/scan/best_practices/http_cookies.go b/scan/best_practices/http_cookies.go index a75aaf0..8790acc 100644 --- a/scan/best_practices/http_cookies.go +++ b/scan/best_practices/http_cookies.go @@ -39,10 +39,12 @@ const ( ) func HTTPCookiesScanHandler(operation *request.Operation, securityScheme auth.SecurityScheme) (*report.ScanReport, error) { - r := report.NewScanReport(HTTPCookiesScanID, HTTPCookiesScanName) + if securityScheme.HasValidValue() { + securityScheme.SetAttackValue(securityScheme.GetValidValue()) + } - securityScheme.SetAttackValue(securityScheme.GetValidValue()) attempt, err := scan.ScanURL(operation, &securityScheme) + r := report.NewScanReport(HTTPCookiesScanID, HTTPCookiesScanName) r.AddScanAttempt(attempt).End() if err != nil { return r, err diff --git a/scan/best_practices/http_headers.go b/scan/best_practices/http_headers.go index e253590..01441ab 100644 --- a/scan/best_practices/http_headers.go +++ b/scan/best_practices/http_headers.go @@ -148,10 +148,12 @@ func CheckCORSAllowOrigin(operation *request.Operation, headers http.Header, r * } func HTTPHeadersBestPracticesScanHandler(operation *request.Operation, ss auth.SecurityScheme) (*report.ScanReport, error) { - r := report.NewScanReport(HTTPHeadersScanID, HTTPHeadersScanName) + if ss.HasValidValue() { + ss.SetAttackValue(ss.GetValidValue()) + } - ss.SetAttackValue(ss.GetValidValue()) vsa, err := scan.ScanURL(operation, &ss) + r := report.NewScanReport(HTTPHeadersScanID, HTTPHeadersScanName) r.AddScanAttempt(vsa).End() if err != nil { return r, err diff --git a/scan/best_practices/http_trace_method.go b/scan/best_practices/http_trace_method.go index 2c45cd7..c9c7365 100644 --- a/scan/best_practices/http_trace_method.go +++ b/scan/best_practices/http_trace_method.go @@ -19,12 +19,15 @@ const ( ) func HTTPTraceMethodScanHandler(operation *request.Operation, ss auth.SecurityScheme) (*report.ScanReport, error) { - r := report.NewScanReport(HTTPTraceScanID, HTTPTraceScanName) + if ss.HasValidValue() { + ss.SetAttackValue(ss.GetValidValue()) + } + newOperation := operation.Clone() newOperation.Method = "TRACE" - ss.SetAttackValue(ss.GetValidValue()) vsa, err := scan.ScanURL(newOperation, &ss) + r := report.NewScanReport(HTTPTraceScanID, HTTPTraceScanName) r.AddScanAttempt(vsa).End() if err != nil { return r, err diff --git a/scan/discover/graphql.go b/scan/discover/graphql.go index 43621e4..b113441 100644 --- a/scan/discover/graphql.go +++ b/scan/discover/graphql.go @@ -61,11 +61,13 @@ func newGetGraphqlIntrospectionRequest(endpoint *url.URL) (*http.Request, error) } func GraphqlIntrospectionScanHandler(operation *request.Operation, securityScheme auth.SecurityScheme) (*report.ScanReport, error) { - r := report.NewScanReport(GraphqlIntrospectionScanID, GraphqlIntrospectionScanName) - securityScheme.SetAttackValue(securityScheme.GetValidValue()) + if securityScheme.HasValidValue() { + securityScheme.SetAttackValue(securityScheme.GetValidValue()) + } base := ExtractBaseURL(operation.Request.URL) + r := report.NewScanReport(GraphqlIntrospectionScanID, GraphqlIntrospectionScanName) for _, path := range potentialGraphQLEndpoints { newRequest, err := newPostGraphqlIntrospectionRequest(base.ResolveReference(&url.URL{Path: path})) if err != nil { diff --git a/scan/discover/server_signature.go b/scan/discover/server_signature.go index 273ccc0..3cb65c6 100644 --- a/scan/discover/server_signature.go +++ b/scan/discover/server_signature.go @@ -44,10 +44,12 @@ func checkSignatureHeader(operation *request.Operation, headers map[string][]str } func ServerSignatureScanHandler(operation *request.Operation, securityScheme auth.SecurityScheme) (*report.ScanReport, error) { - r := report.NewScanReport(DiscoverServerSignatureScanID, DiscoverServerSignatureScanName) + if securityScheme.HasValidValue() { + securityScheme.SetAttackValue(securityScheme.GetValidValue()) + } - securityScheme.SetAttackValue(securityScheme.GetValidValue()) vsa, err := scan.ScanURL(operation, &securityScheme) + r := report.NewScanReport(DiscoverServerSignatureScanID, DiscoverServerSignatureScanName) r.AddScanAttempt(vsa).End() if err != nil { return r, err diff --git a/scan/jwt/alg_none.go b/scan/jwt/alg_none.go index 0dcc805..3163dc2 100644 --- a/scan/jwt/alg_none.go +++ b/scan/jwt/alg_none.go @@ -22,16 +22,21 @@ const ( ) func AlgNoneJwtScanHandler(operation *request.Operation, ss auth.SecurityScheme) (*report.ScanReport, error) { - r := report.NewScanReport(AlgNoneJwtScanID, AlgNoneJwtScanName) if !ShouldBeScanned(ss) { - return r, nil + return nil, nil } - valueWriter := ss.GetValidValueWriter().(*jwt.JWTWriter) - if valueWriter.Token.Method.Alg() == jwtlib.SigningMethodNone.Alg() { - return r, nil + var valueWriter *jwt.JWTWriter + if ss.HasValidValue() { + valueWriter = ss.GetValidValueWriter().(*jwt.JWTWriter) + if valueWriter.Token.Method.Alg() == jwtlib.SigningMethodNone.Alg() { + return nil, nil + } + } else { + valueWriter, _ = jwt.NewJWTWriter(jwt.FakeJWT) } + r := report.NewScanReport(AlgNoneJwtScanID, AlgNoneJwtScanName) newToken, err := valueWriter.WithAlgNone() if err != nil { return r, err diff --git a/scan/jwt/alg_none_test.go b/scan/jwt/alg_none_test.go index 8ca6572..15df762 100644 --- a/scan/jwt/alg_none_test.go +++ b/scan/jwt/alg_none_test.go @@ -1,6 +1,7 @@ package jwt_test import ( + "net/http" "testing" "github.com/cerberauth/vulnapi/internal/auth" @@ -10,19 +11,35 @@ import ( "github.com/stretchr/testify/assert" ) -func TestAlgNoneJwtScanHandlerWithoutJwt(t *testing.T) { +func TestAlgNoneJwtScanHandlerWithoutSecurityScheme(t *testing.T) { httpmock.Activate() defer httpmock.DeactivateAndReset() securityScheme := auth.NewNoAuthSecurityScheme() operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) - httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(405, nil)) + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) report, err := jwt.AlgNoneJwtScanHandler(operation, securityScheme) assert.NoError(t, err) assert.Equal(t, 0, httpmock.GetTotalCallCount()) + assert.Nil(t, report) +} + +func TestAlgNoneJwtScanHandlerWithoutJWT(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + securityScheme, _ := auth.NewAuthorizationJWTBearerSecurityScheme("token", nil) + operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) + + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) + + report, err := jwt.AlgNoneJwtScanHandler(operation, securityScheme) + + assert.NoError(t, err) + assert.Equal(t, 1, httpmock.GetTotalCallCount()) assert.False(t, report.HasVulnerabilityReport()) } @@ -34,7 +51,7 @@ func TestAlgNoneJwtScanHandler(t *testing.T) { securityScheme, _ := auth.NewAuthorizationJWTBearerSecurityScheme("token", &token) operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) - httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(401, nil)) + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) report, err := jwt.AlgNoneJwtScanHandler(operation, securityScheme) diff --git a/scan/jwt/blank_secret.go b/scan/jwt/blank_secret.go index 8b2a818..5aa0898 100644 --- a/scan/jwt/blank_secret.go +++ b/scan/jwt/blank_secret.go @@ -21,13 +21,18 @@ const ( ) func BlankSecretScanHandler(operation *request.Operation, ss auth.SecurityScheme) (*report.ScanReport, error) { - r := report.NewScanReport(BlankSecretVulnerabilityScanID, BlankSecretVulnerabilityScanName) if !ShouldBeScanned(ss) { - r.End() - return r, nil + return nil, nil + } + + var valueWriter *jwt.JWTWriter + if ss.HasValidValue() { + valueWriter = ss.GetValidValueWriter().(*jwt.JWTWriter) + } else { + valueWriter, _ = jwt.NewJWTWriter(jwt.FakeJWT) } - valueWriter := ss.GetValidValueWriter().(*jwt.JWTWriter) + r := report.NewScanReport(BlankSecretVulnerabilityScanID, BlankSecretVulnerabilityScanName) newToken, err := valueWriter.SignWithKey([]byte("")) if err != nil { return r, err diff --git a/scan/jwt/blank_secret_test.go b/scan/jwt/blank_secret_test.go index 82b4f3a..7772e0e 100644 --- a/scan/jwt/blank_secret_test.go +++ b/scan/jwt/blank_secret_test.go @@ -1,6 +1,7 @@ package jwt_test import ( + "net/http" "testing" "github.com/cerberauth/vulnapi/internal/auth" @@ -10,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestBlankSecretScanHandlerWithoutJwt(t *testing.T) { +func TestBlankSecretScanHandlerWithoutSecurityScheme(t *testing.T) { securityScheme := auth.NewNoAuthSecurityScheme() operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) @@ -18,6 +19,22 @@ func TestBlankSecretScanHandlerWithoutJwt(t *testing.T) { assert.NoError(t, err) assert.Equal(t, 0, httpmock.GetTotalCallCount()) + assert.Nil(t, report) +} + +func TestBlankSecretScanHandlerWithoutJWT(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + securityScheme, _ := auth.NewAuthorizationJWTBearerSecurityScheme("token", nil) + operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) + + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) + + report, err := jwt.BlankSecretScanHandler(operation, securityScheme) + + assert.NoError(t, err) + assert.Equal(t, 1, httpmock.GetTotalCallCount()) assert.False(t, report.HasVulnerabilityReport()) } @@ -29,7 +46,7 @@ func TestBlankSecretScanHandler(t *testing.T) { securityScheme, _ := auth.NewAuthorizationJWTBearerSecurityScheme("token", &token) operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) - httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(401, nil)) + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) report, err := jwt.BlankSecretScanHandler(operation, securityScheme) diff --git a/scan/jwt/not_verified.go b/scan/jwt/not_verified.go index 04c756a..fa75aff 100644 --- a/scan/jwt/not_verified.go +++ b/scan/jwt/not_verified.go @@ -21,12 +21,17 @@ const ( ) func NotVerifiedScanHandler(operation *request.Operation, ss auth.SecurityScheme) (*report.ScanReport, error) { - r := report.NewScanReport(NotVerifiedJwtScanID, NotVerifiedJwtScanName) if !ShouldBeScanned(ss) { - return r, nil + return nil, nil + } + + if !ss.HasValidValue() { + return nil, nil } valueWriter := ss.GetValidValueWriter().(*jwt.JWTWriter) + + r := report.NewScanReport(NotVerifiedJwtScanID, NotVerifiedJwtScanName) newToken, err := valueWriter.SignWithMethodAndRandomKey(valueWriter.Token.Method) if err != nil { return r, err diff --git a/scan/jwt/not_verified_test.go b/scan/jwt/not_verified_test.go index 08dc933..77db0c9 100644 --- a/scan/jwt/not_verified_test.go +++ b/scan/jwt/not_verified_test.go @@ -11,20 +11,36 @@ import ( "github.com/stretchr/testify/assert" ) -func TestNotVerifiedScanHandlerWithoutJwt(t *testing.T) { +func TestNotVerifiedScanHandlerWithoutSecurityScheme(t *testing.T) { httpmock.Activate() defer httpmock.DeactivateAndReset() securityScheme := auth.NewNoAuthSecurityScheme() operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) - httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(405, nil)) + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) report, err := jwt.NotVerifiedScanHandler(operation, securityScheme) assert.NoError(t, err) assert.Equal(t, 0, httpmock.GetTotalCallCount()) - assert.False(t, report.HasVulnerabilityReport()) + assert.Nil(t, report) +} + +func TestNotVerifiedScanHandlerWithoutJWT(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + securityScheme, _ := auth.NewAuthorizationJWTBearerSecurityScheme("token", nil) + operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) + + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) + + report, err := jwt.NotVerifiedScanHandler(operation, securityScheme) + + assert.NoError(t, err) + assert.Equal(t, 0, httpmock.GetTotalCallCount()) + assert.Nil(t, report) } func TestNotVerifiedScanHandler(t *testing.T) { @@ -37,8 +53,8 @@ func TestNotVerifiedScanHandler(t *testing.T) { httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.ResponderFromMultipleResponses( []*http.Response{ - httpmock.NewBytesResponse(200, nil), - httpmock.NewBytesResponse(401, nil), + httpmock.NewBytesResponse(http.StatusOK, nil), + httpmock.NewBytesResponse(http.StatusUnauthorized, nil), }, t.Log), ) report, err := jwt.NotVerifiedScanHandler(operation, securityScheme) @@ -58,8 +74,8 @@ func TestNotVerifiedScanHandlerWithNotVerifiedJWT(t *testing.T) { httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.ResponderFromMultipleResponses( []*http.Response{ - httpmock.NewBytesResponse(200, nil), - httpmock.NewBytesResponse(200, nil), + httpmock.NewBytesResponse(http.StatusOK, nil), + httpmock.NewBytesResponse(http.StatusOK, nil), }, t.Log), ) report, err := jwt.NotVerifiedScanHandler(operation, securityScheme) @@ -79,8 +95,8 @@ func TestNotVerifiedScanHandlerWhenHTTPCodeIs401(t *testing.T) { httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.ResponderFromMultipleResponses( []*http.Response{ - httpmock.NewBytesResponse(401, nil), - httpmock.NewBytesResponse(401, nil), + httpmock.NewBytesResponse(http.StatusUnauthorized, nil), + httpmock.NewBytesResponse(http.StatusUnauthorized, nil), }, t.Log), ) report, err := jwt.NotVerifiedScanHandler(operation, securityScheme) diff --git a/scan/jwt/null_signature.go b/scan/jwt/null_signature.go index 519318f..aab2010 100644 --- a/scan/jwt/null_signature.go +++ b/scan/jwt/null_signature.go @@ -21,12 +21,18 @@ const ( ) func NullSignatureScanHandler(operation *request.Operation, ss auth.SecurityScheme) (*report.ScanReport, error) { - r := report.NewScanReport(NullSignatureScanID, NullSignatureScanName) if !ShouldBeScanned(ss) { - return r, nil + return nil, nil + } + + var valueWriter *jwt.JWTWriter + if ss.HasValidValue() { + valueWriter = ss.GetValidValueWriter().(*jwt.JWTWriter) + } else { + valueWriter, _ = jwt.NewJWTWriter(jwt.FakeJWT) } - valueWriter := ss.GetValidValueWriter().(*jwt.JWTWriter) + r := report.NewScanReport(NullSignatureScanID, NullSignatureScanName) newToken, err := valueWriter.WithoutSignature() if err != nil { return r, err diff --git a/scan/jwt/null_signature_test.go b/scan/jwt/null_signature_test.go index fc3045f..73c92a4 100644 --- a/scan/jwt/null_signature_test.go +++ b/scan/jwt/null_signature_test.go @@ -1,6 +1,7 @@ package jwt_test import ( + "net/http" "testing" "github.com/cerberauth/vulnapi/internal/auth" @@ -10,19 +11,35 @@ import ( "github.com/stretchr/testify/assert" ) -func TestNullSignatureScanHandlerWithoutJwt(t *testing.T) { +func TestNullSignatureScanHandlerWithoutSecurityScheme(t *testing.T) { httpmock.Activate() defer httpmock.DeactivateAndReset() securityScheme := auth.NewNoAuthSecurityScheme() operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) - httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(405, nil)) + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) report, err := jwt.NullSignatureScanHandler(operation, securityScheme) assert.NoError(t, err) assert.Equal(t, 0, httpmock.GetTotalCallCount()) + assert.Nil(t, report) +} + +func TestNullSignatureScanHandlerWithoutJWT(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + securityScheme, _ := auth.NewAuthorizationJWTBearerSecurityScheme("token", nil) + operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) + + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) + + report, err := jwt.NullSignatureScanHandler(operation, securityScheme) + + assert.NoError(t, err) + assert.Equal(t, 1, httpmock.GetTotalCallCount()) assert.False(t, report.HasVulnerabilityReport()) } @@ -34,7 +51,7 @@ func TestNullSignatureScanHandler(t *testing.T) { securityScheme, _ := auth.NewAuthorizationJWTBearerSecurityScheme("token", &token) operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) - httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(401, nil)) + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) report, err := jwt.NullSignatureScanHandler(operation, securityScheme) diff --git a/scan/jwt/weak_secret.go b/scan/jwt/weak_secret.go index cdd649d..d499e05 100644 --- a/scan/jwt/weak_secret.go +++ b/scan/jwt/weak_secret.go @@ -26,17 +26,20 @@ var defaultJwtSecretDictionary = []string{"secret", "password", "123456", "chang const jwtSecretDictionarySeclistUrl = "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/scraped-JWT-secrets.txt" func WeakHMACSecretScanHandler(o *request.Operation, ss auth.SecurityScheme) (*report.ScanReport, error) { - r := report.NewScanReport(WeakSecretVulnerabilityScanID, WeakSecretVulnerabilityScanName) if !ShouldBeScanned(ss) { - r.End() - return r, nil + return nil, nil + } + + if !ss.HasValidValue() { + return nil, nil } valueWriter := ss.GetValidValueWriter().(*jwt.JWTWriter) if !valueWriter.IsHMACAlg() { - return r, nil + return nil, nil } + r := report.NewScanReport(WeakSecretVulnerabilityScanID, WeakSecretVulnerabilityScanName) jwtSecretDictionary := defaultJwtSecretDictionary if secretDictionnaryFromSeclist, err := seclist.NewSecListFromURL("JWT Secrets Dictionnary", jwtSecretDictionarySeclistUrl); err == nil { jwtSecretDictionary = secretDictionnaryFromSeclist.Items diff --git a/scan/jwt/weak_secret_test.go b/scan/jwt/weak_secret_test.go index 1249039..b7d2de7 100644 --- a/scan/jwt/weak_secret_test.go +++ b/scan/jwt/weak_secret_test.go @@ -1,6 +1,7 @@ package jwt_test import ( + "net/http" "testing" "github.com/cerberauth/vulnapi/internal/auth" @@ -10,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestWeakHMACSecretScanHandlerWithoutJwt(t *testing.T) { +func TestWeakHMACSecretScanHandlerWithoutSecurityScheme(t *testing.T) { securityScheme := auth.NewNoAuthSecurityScheme() operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) @@ -18,7 +19,7 @@ func TestWeakHMACSecretScanHandlerWithoutJwt(t *testing.T) { assert.NoError(t, err) assert.Equal(t, 0, httpmock.GetTotalCallCount()) - assert.False(t, report.HasVulnerabilityReport()) + assert.Nil(t, report) } func TestWeakHMACSecretScanHandlerWithJWTUsingOtherAlg(t *testing.T) { @@ -30,7 +31,23 @@ func TestWeakHMACSecretScanHandlerWithJWTUsingOtherAlg(t *testing.T) { assert.NoError(t, err) assert.Equal(t, 0, httpmock.GetTotalCallCount()) - assert.False(t, report.HasVulnerabilityReport()) + assert.Nil(t, report) +} + +func TestWeakHMACSecretScanHandlerWithoutJWT(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + securityScheme, _ := auth.NewAuthorizationJWTBearerSecurityScheme("token", nil) + operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) + + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) + + report, err := jwt.WeakHMACSecretScanHandler(operation, securityScheme) + + assert.NoError(t, err) + assert.Equal(t, 0, httpmock.GetTotalCallCount()) + assert.Nil(t, report) } func TestWeakHMACSecretScanHandlerWithWeakJWT(t *testing.T) { @@ -41,7 +58,7 @@ func TestWeakHMACSecretScanHandlerWithWeakJWT(t *testing.T) { securityScheme, _ := auth.NewAuthorizationJWTBearerSecurityScheme("token", &token) operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) - httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(104, nil)) + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusOK, nil)) report, err := jwt.WeakHMACSecretScanHandler(operation, securityScheme) @@ -55,10 +72,10 @@ func TestWeakHMACSecretScanHandlerWithStrongerJWT(t *testing.T) { defer httpmock.DeactivateAndReset() token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.MWUarT7Q4e5DqnZbdr7VKw3rx9VW-CrvoVkfpllS4CY" - securityScheme := auth.NewAuthorizationBearerSecurityScheme("token", &token) + securityScheme, _ := auth.NewAuthorizationJWTBearerSecurityScheme("token", &token) operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil) - httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(104, nil)) + httpmock.RegisterResponder(operation.Method, operation.Request.URL.String(), httpmock.NewBytesResponder(http.StatusUnauthorized, nil)) report, err := jwt.WeakHMACSecretScanHandler(operation, securityScheme)