mirror of
https://github.com/versity/versitygw.git
synced 2026-05-23 12:21:28 +00:00
fix: reject invalid PostObject keys
Validate multipart PostObject key fields with the existing object name rules so path traversal and degenerate names return BadRequest. This prevents crafted object keys from escaping the gateway root.
This commit is contained in:
@@ -112,15 +112,7 @@ func (c S3ApiController) POSTObject(ctx *fiber.Ctx) (*Response, error) {
|
||||
cacheControl := parsed.Fields["cache-control"]
|
||||
expires := parsed.Fields["expires"]
|
||||
|
||||
key, ok := parsed.Fields["key"]
|
||||
if !ok || key == "" {
|
||||
debuglogger.Logf("missing object key")
|
||||
return &Response{
|
||||
MetaOpts: &MetaOptions{
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
},
|
||||
}, s3err.PostAuth.MissingField("key")
|
||||
}
|
||||
key := parsed.Fields["key"]
|
||||
|
||||
err := auth.VerifyAccess(ctx.Context(), c.be,
|
||||
auth.AccessOptions{
|
||||
|
||||
@@ -254,28 +254,6 @@ func TestS3ApiController_POSTObject(t *testing.T) {
|
||||
input testInput
|
||||
output testOutput
|
||||
}{
|
||||
{
|
||||
name: "missing key",
|
||||
input: testInput{
|
||||
locals: postObjectLocalsForTest(middlewares.PostObjectResult{
|
||||
Fields: map[string]string{
|
||||
"policy": basePolicy,
|
||||
"file": "ignored",
|
||||
"x-amz-signature": "ignored",
|
||||
},
|
||||
FileRdr: newMockFileReader("payload"),
|
||||
ContentLength: int64(len("payload")),
|
||||
}),
|
||||
},
|
||||
output: testOutput{
|
||||
response: &Response{
|
||||
MetaOpts: &MetaOptions{
|
||||
BucketOwner: "root",
|
||||
},
|
||||
},
|
||||
err: s3err.PostAuth.MissingField("key"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "verify access fails",
|
||||
input: testInput{
|
||||
|
||||
@@ -86,6 +86,16 @@ func AuthorizePostObject(root RootUserConfig, iam auth.IAMService, region string
|
||||
|
||||
fields := result.Fields
|
||||
|
||||
if fields["key"] == "" {
|
||||
debuglogger.Logf("missing object key")
|
||||
return s3err.PostAuth.MissingField("key")
|
||||
}
|
||||
|
||||
if !utils.IsObjectNameValid(fields["key"]) {
|
||||
debuglogger.Logf("invalid POST object key: %q", fields["key"])
|
||||
return s3err.GetAPIError(s3err.ErrBadRequest)
|
||||
}
|
||||
|
||||
policyB64 := fields[formFieldPolicy]
|
||||
algorithm := fields[formFieldAlgorithm]
|
||||
credentialStr := fields[formFieldCredential]
|
||||
|
||||
@@ -309,6 +309,44 @@ func PostObject_access_denied(s *S3Conf) error {
|
||||
})
|
||||
}
|
||||
|
||||
func PostObject_invalid_object_names(s *S3Conf) error {
|
||||
testName := "PostObject_invalid_object_names"
|
||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||
for _, obj := range []string{
|
||||
".",
|
||||
"..",
|
||||
"./",
|
||||
"/.",
|
||||
"//",
|
||||
"../",
|
||||
"/..",
|
||||
"../.",
|
||||
"../../../.",
|
||||
"../../../etc/passwd",
|
||||
"../../../../tmp/foo",
|
||||
"for/../../bar/",
|
||||
"a/a/a/../../../../../etc/passwd",
|
||||
"/a/../../b/../../c/../../../etc/passwd",
|
||||
} {
|
||||
resp, err := sendPostObject(PostRequestConfig{
|
||||
bucket: bucket,
|
||||
key: obj,
|
||||
s3Conf: s,
|
||||
fileContent: []byte("data"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkHTTPResponseApiErr(resp, s3err.GetAPIError(s3err.ErrBadRequest)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func PostObject_policy_access_control(s *S3Conf) error {
|
||||
testName := "PostObject_policy_access_control"
|
||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||
|
||||
@@ -1196,6 +1196,7 @@ func TestPostObject(ts *TestState) {
|
||||
ts.Run(PostObject_signature_mismatch)
|
||||
ts.Run(PostObject_expired_due_to_date)
|
||||
ts.Run(PostObject_access_denied)
|
||||
ts.Run(PostObject_invalid_object_names)
|
||||
ts.Run(PostObject_policy_access_control)
|
||||
ts.Run(PostObject_policy_expired)
|
||||
ts.Run(PostObject_invalid_policy_document)
|
||||
@@ -2038,6 +2039,7 @@ func GetIntTests() IntTests {
|
||||
"PostObject_signature_mismatch": PostObject_signature_mismatch,
|
||||
"PostObject_expired_due_to_date": PostObject_expired_due_to_date,
|
||||
"PostObject_access_denied": PostObject_access_denied,
|
||||
"PostObject_invalid_object_names": PostObject_invalid_object_names,
|
||||
"PostObject_policy_access_control": PostObject_policy_access_control,
|
||||
"PostObject_policy_expired": PostObject_policy_expired,
|
||||
"PostObject_invalid_policy_document": PostObject_invalid_policy_document,
|
||||
|
||||
Reference in New Issue
Block a user