Files
seaweedFS/weed/s3api/s3api_auth.go
Chris Lu 7a18c3a16f Fix critical authentication bypass vulnerability (#7912) (#7915)
* Fix critical authentication bypass vulnerability (#7912)

The isRequestPostPolicySignatureV4() function was incorrectly returning
true for ANY POST request with multipart/form-data content type,
causing all such requests to bypass authentication in authRequest().

This allowed unauthenticated access to S3 API endpoints, as reported
in issue #7912 where any credentials (or no credentials) were accepted.

The fix removes isRequestPostPolicySignatureV4() entirely, preventing
authTypePostPolicy from ever being set. PostPolicy signature verification
is still properly handled in PostPolicyBucketHandler via
doesPolicySignatureMatch().

Fixes #7912

* add AuthPostPolicy

* refactor

* Optimizing Auth Credentials

* Update auth_credentials.go

* Update auth_credentials.go
2025-12-30 12:40:59 -08:00

106 lines
2.8 KiB
Go

package s3api
import (
"net/http"
"strings"
)
// AWS Signature Version '4' constants.
const (
signV4Algorithm = "AWS4-HMAC-SHA256"
signV2Algorithm = "AWS"
iso8601Format = "20060102T150405Z"
yyyymmdd = "20060102"
)
// Verify if request has JWT.
func isRequestJWT(r *http.Request) bool {
return strings.HasPrefix(r.Header.Get("Authorization"), "Bearer")
}
// Verify if request has AWS Signature Version '4'.
func isRequestSignatureV4(r *http.Request) bool {
return strings.HasPrefix(r.Header.Get("Authorization"), signV4Algorithm)
}
// Verify if request has AWS Signature Version '2'.
func isRequestSignatureV2(r *http.Request) bool {
return !strings.HasPrefix(r.Header.Get("Authorization"), signV4Algorithm) &&
strings.HasPrefix(r.Header.Get("Authorization"), signV2Algorithm)
}
// Verify if request has AWS PreSign Version '4'.
func isRequestPresignedSignatureV4(r *http.Request) bool {
_, ok := r.URL.Query()["X-Amz-Credential"]
return ok
}
// Verify request has AWS PreSign Version '2'.
func isRequestPresignedSignatureV2(r *http.Request) bool {
_, ok := r.URL.Query()["AWSAccessKeyId"]
return ok
}
// Verify if the request has AWS Streaming Signature Version '4'. This is only valid for 'PUT' operation.
// Supports both with and without trailer variants:
// - STREAMING-AWS4-HMAC-SHA256-PAYLOAD (original)
// - STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER (with trailing checksums)
func isRequestSignStreamingV4(r *http.Request) bool {
if r.Method != http.MethodPut {
return false
}
contentSha256 := r.Header.Get("x-amz-content-sha256")
return contentSha256 == streamingContentSHA256 || contentSha256 == streamingContentSHA256Trailer
}
func isRequestUnsignedStreaming(r *http.Request) bool {
if r.Method != http.MethodPut {
return false
}
return r.Header.Get("x-amz-content-sha256") == streamingUnsignedPayload
}
// Authorization type.
type authType int
// List of all supported auth types.
const (
authTypeUnknown authType = iota
authTypeAnonymous
authTypePresigned
authTypePresignedV2
authTypePostPolicy
authTypeStreamingSigned
authTypeStreamingUnsigned
authTypeSigned
authTypeSignedV2
authTypeJWT
)
// Get request authentication type.
func getRequestAuthType(r *http.Request) authType {
var authType authType
if isRequestSignatureV2(r) {
authType = authTypeSignedV2
} else if isRequestPresignedSignatureV2(r) {
authType = authTypePresignedV2
} else if isRequestSignStreamingV4(r) {
authType = authTypeStreamingSigned
} else if isRequestUnsignedStreaming(r) {
authType = authTypeStreamingUnsigned
} else if isRequestSignatureV4(r) {
authType = authTypeSigned
} else if isRequestPresignedSignatureV4(r) {
authType = authTypePresigned
} else if isRequestJWT(r) {
authType = authTypeJWT
} else if _, ok := r.Header["Authorization"]; !ok {
authType = authTypeAnonymous
} else {
authType = authTypeUnknown
}
return authType
}