Merge pull request #2114 from versity/sis/unsupported-sigv2

fix: reject SigV2 requests
This commit is contained in:
Ben McClelland
2026-05-06 13:38:14 -07:00
committed by GitHub
8 changed files with 100 additions and 4 deletions
+4
View File
@@ -53,6 +53,10 @@ func VerifyV4Signature(root RootUserConfig, iam auth.IAMService, region string,
// Check X-Amz-Date header
date := ctx.Get("X-Amz-Date")
if date == "" {
// Fall back to `Date` header if `X-Amz-Date` is not set
date = ctx.Get("Date")
}
if date == "" {
return s3err.GetAPIError(s3err.ErrMissingDateHeader)
}
+4
View File
@@ -35,6 +35,10 @@ func VerifyPresignedV4Signature(root RootUserConfig, iam auth.IAMService, region
if !utils.IsPresignedURLAuth(ctx) {
return nil
}
if utils.IsPresignedURLAuthV2(ctx) {
// SigV2 authorization is not supported by the gateway
return s3err.GetAPIError(s3err.ErrUnsupportedAuthorizationMechanism)
}
if ctx.Request().URI().QueryArgs().Has("X-Amz-Security-Token") {
// OIDC Authorization with X-Amz-Security-Token is not supported
+4 -1
View File
@@ -191,7 +191,10 @@ func ParseAuthorization(authorization string) (AuthData, error) {
}
algo := authParts[0]
if algo == "AWS" {
// SigV2 authorization is not supported by the gateway
return a, s3err.GetAPIError(s3err.ErrUnsupportedAuthorizationMechanism)
}
if algo != "AWS4-HMAC-SHA256" {
return a, s3err.GetAPIError(s3err.ErrUnsupportedAuthorizationType)
}
+24 -3
View File
@@ -254,11 +254,21 @@ func IsPresignedURLAuth(ctx *fiber.Ctx) bool {
signedHeaders := ctx.Query("X-Amz-SignedHeaders")
expires := ctx.Query("X-Amz-Expires")
return !isEmpty(algo, creds, signature, signedHeaders, expires)
return !allEmpty(algo, creds, signature, signedHeaders, expires) || IsPresignedURLAuthV2(ctx)
}
// isEmpty checks if all the given strings are empty
func isEmpty(args ...string) bool {
// IsPresignedURLAuthV2 determines if the request is
// query-string signed with aws v2 signer
func IsPresignedURLAuthV2(ctx *fiber.Ctx) bool {
expires := ctx.Query("Expires")
access := ctx.Query("AWSAccessKeyId")
signature := ctx.Query("Signature")
return anyNonEmpty(expires, access, signature)
}
// allEmpty reports whether every given string is empty.
func allEmpty(args ...string) bool {
for _, a := range args {
if a != "" {
return false
@@ -267,3 +277,14 @@ func isEmpty(args ...string) bool {
return true
}
// anyNonEmpty reports whether at least one given string is non-empty.
func anyNonEmpty(args ...string) bool {
for _, a := range args {
if a != "" {
return true
}
}
return false
}
+6
View File
@@ -190,6 +190,7 @@ const (
ErrMetadataTooLarge
ErrOnlyAws4HmacSha256
ErrInvalidDateHeader
ErrUnsupportedAuthorizationMechanism
// Non-AWS errors
ErrExistingObjectIsDirectory
@@ -868,6 +869,11 @@ var errorCodeResponse = map[ErrorCode]APIError{
Description: "X-Amz-Date must be formated via ISO8601 Long format",
HTTPStatusCode: http.StatusBadRequest,
},
ErrUnsupportedAuthorizationMechanism: {
Code: "InvalidRequest",
Description: "The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.",
HTTPStatusCode: http.StatusBadRequest,
},
// non aws errors
ErrExistingObjectIsDirectory: {
+4
View File
@@ -38,6 +38,7 @@ func TestAuthentication(ts *TestState) {
ts.Run(Authentication_invalid_sha256_payload_hash)
ts.Run(Authentication_md5)
ts.Run(Authentication_signature_error_incorrect_secret_key)
ts.Run(Authentication_sigv2_not_supported)
ts.Run(Authentication_with_expect_header)
}
@@ -62,6 +63,7 @@ func TestPresignedAuthentication(ts *TestState) {
ts.Run(PresignedAuth_exceeding_expiration_query_param)
ts.Run(PresignedAuth_expired_request)
ts.Run(PresignedAuth_incorrect_secret_key)
ts.Run(PresignedAuth_sigv2_not_supported)
ts.Run(PresignedAuth_PutObject_success)
ts.Run(PresignedAuth_Put_GetObject_with_data)
if !ts.conf.azureTests {
@@ -1293,6 +1295,7 @@ func GetIntTests() IntTests {
"Authentication_invalid_sha256_payload_hash": Authentication_invalid_sha256_payload_hash,
"Authentication_md5": Authentication_md5,
"Authentication_signature_error_incorrect_secret_key": Authentication_signature_error_incorrect_secret_key,
"Authentication_sigv2_not_supported": Authentication_sigv2_not_supported,
"Authentication_with_expect_header": Authentication_with_expect_header,
"PresignedAuth_security_token_not_supported": PresignedAuth_security_token_not_supported,
"PresignedAuth_unsupported_algorithm": PresignedAuth_unsupported_algorithm,
@@ -1314,6 +1317,7 @@ func GetIntTests() IntTests {
"PresignedAuth_exceeding_expiration_query_param": PresignedAuth_exceeding_expiration_query_param,
"PresignedAuth_expired_request": PresignedAuth_expired_request,
"PresignedAuth_incorrect_secret_key": PresignedAuth_incorrect_secret_key,
"PresignedAuth_sigv2_not_supported": PresignedAuth_sigv2_not_supported,
"PresignedAuth_PutObject_success": PresignedAuth_PutObject_success,
"PutObject_missing_object_lock_retention_config": PutObject_missing_object_lock_retention_config,
"PutObject_name_too_long": PutObject_name_too_long,
+23
View File
@@ -665,6 +665,29 @@ func PresignedAuth_incorrect_secret_key(s *S3Conf) error {
})
}
func PresignedAuth_sigv2_not_supported(s *S3Conf) error {
testName := "PresignedAuth_sigv2_not_supported"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
expires := time.Now().UTC().Add(time.Hour).Unix()
uri := fmt.Sprintf("%s/%s/object?AWSAccessKeyId=%s&Expires=%d&Signature=my-signature", s.endpoint, bucket, s.awsID, expires)
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil)
if err != nil {
cancel()
return err
}
resp, err := s.httpClient.Do(req)
cancel()
if err != nil {
return err
}
return checkHTTPResponseApiErr(resp, s3err.GetAPIError(s3err.ErrUnsupportedAuthorizationMechanism))
})
}
func PresignedAuth_PutObject_success(s *S3Conf) error {
testName := "PresignedAuth_PutObject_success"
return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error {
+31
View File
@@ -564,6 +564,37 @@ func Authentication_signature_error_incorrect_secret_key(s *S3Conf) error {
})
}
func Authentication_sigv2_not_supported(s *S3Conf) error {
testName := "Authentication_sigv2_not_supported"
bucket := getBucketName()
return authHandler(s, &authConfig{
testName: testName,
method: http.MethodPut,
service: "s3",
date: time.Now(),
path: fmt.Sprintf("%s/object", bucket),
}, func(req *http.Request) error {
err := setup(s, bucket)
if err != nil {
return err
}
req.Header.Del("Authorization")
req.Header.Set("Authorization", "AWS seed_signature")
resp, err := s.httpClient.Do(req)
if err != nil {
return err
}
if err := checkHTTPResponseApiErr(resp, s3err.GetAPIError(s3err.ErrUnsupportedAuthorizationMechanism)); err != nil {
return err
}
return teardown(s, bucket)
})
}
func Authentication_with_expect_header(s *S3Conf) error {
testName := "Authentication_with_expect_header"
bucket, object := getBucketName(), "object"