mirror of
https://github.com/minio/minio.git
synced 2025-03-30 17:23:42 -04:00
accessPolicy: prevent backdoor ListBucket via brute-force 404s, per docs + small fixes
* accessPolicy: copy object should require PutObject * accessPolicy: cite mpu perms doc only for relevant operations * accessPolicy: prevent backdoor ListBucket via brute-force 404s, per docs
This commit is contained in:
parent
8b4a5f07b4
commit
e8cd1aad8d
@ -32,7 +32,7 @@ import (
|
|||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
||||||
func enforceBucketPolicy(action string, bucket string, reqURL *url.URL) (s3Error APIErrorCode) {
|
func enforceBucketPolicy(action string, bucket string, reqURL *url.URL) (s3Error APIErrorCode) {
|
||||||
// Read saved bucket policy.
|
// Read saved bucket policy.
|
||||||
policy, err := readBucketPolicy(bucket)
|
policy, err := readBucketPolicy(bucket)
|
||||||
@ -84,7 +84,7 @@ func (api objectStorageAPI) GetBucketLocationHandler(w http.ResponseWriter, r *h
|
|||||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
||||||
return
|
return
|
||||||
case authTypeAnonymous:
|
case authTypeAnonymous:
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
||||||
if s3Error := enforceBucketPolicy("s3:GetBucketLocation", bucket, r.URL); s3Error != ErrNone {
|
if s3Error := enforceBucketPolicy("s3:GetBucketLocation", bucket, r.URL); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||||
return
|
return
|
||||||
@ -233,7 +233,7 @@ func (api objectStorageAPI) ListObjectsHandler(w http.ResponseWriter, r *http.Re
|
|||||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
||||||
return
|
return
|
||||||
case authTypeAnonymous:
|
case authTypeAnonymous:
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
||||||
if s3Error := enforceBucketPolicy("s3:ListBucket", bucket, r.URL); s3Error != ErrNone {
|
if s3Error := enforceBucketPolicy("s3:ListBucket", bucket, r.URL); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||||
return
|
return
|
||||||
@ -364,7 +364,7 @@ func (api objectStorageAPI) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
|||||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
||||||
return
|
return
|
||||||
case authTypeAnonymous:
|
case authTypeAnonymous:
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
||||||
if s3Error := enforceBucketPolicy("s3:DeleteObject", bucket, r.URL); s3Error != ErrNone {
|
if s3Error := enforceBucketPolicy("s3:DeleteObject", bucket, r.URL); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||||
return
|
return
|
||||||
|
@ -51,6 +51,24 @@ func setGetRespHeaders(w http.ResponseWriter, reqParams url.Values) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// errAllowableNotFound - For an anon user, return 404 if have ListBucket, 403 otherwise
|
||||||
|
// this is in keeping with the permissions sections of the docs of both:
|
||||||
|
// HEAD Object: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectHEAD.html
|
||||||
|
// GET Object: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html
|
||||||
|
func errAllowableObjectNotFound(bucket string, r *http.Request) APIErrorCode {
|
||||||
|
if getRequestAuthType(r) == authTypeAnonymous {
|
||||||
|
//we care about the bucket as a whole, not a particular resource
|
||||||
|
url := *r.URL
|
||||||
|
url.Path = "/" + bucket
|
||||||
|
|
||||||
|
if s3Error := enforceBucketPolicy("s3:ListBucket", bucket, &url); s3Error != ErrNone {
|
||||||
|
return ErrAccessDenied
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrNoSuchKey
|
||||||
|
}
|
||||||
|
|
||||||
// GetObjectHandler - GET Object
|
// GetObjectHandler - GET Object
|
||||||
// ----------
|
// ----------
|
||||||
// This implementation of the GET operation retrieves object. To use GET,
|
// This implementation of the GET operation retrieves object. To use GET,
|
||||||
@ -67,7 +85,7 @@ func (api objectStorageAPI) GetObjectHandler(w http.ResponseWriter, r *http.Requ
|
|||||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
||||||
return
|
return
|
||||||
case authTypeAnonymous:
|
case authTypeAnonymous:
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
||||||
if s3Error := enforceBucketPolicy("s3:GetObject", bucket, r.URL); s3Error != ErrNone {
|
if s3Error := enforceBucketPolicy("s3:GetObject", bucket, r.URL); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||||
return
|
return
|
||||||
@ -87,7 +105,7 @@ func (api objectStorageAPI) GetObjectHandler(w http.ResponseWriter, r *http.Requ
|
|||||||
case BucketNotFound:
|
case BucketNotFound:
|
||||||
writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
|
writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
|
||||||
case ObjectNotFound:
|
case ObjectNotFound:
|
||||||
writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
|
writeErrorResponse(w, r, errAllowableObjectNotFound(bucket, r), r.URL.Path)
|
||||||
case ObjectNameInvalid:
|
case ObjectNameInvalid:
|
||||||
writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
|
writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
|
||||||
default:
|
default:
|
||||||
@ -254,7 +272,7 @@ func (api objectStorageAPI) HeadObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
||||||
return
|
return
|
||||||
case authTypeAnonymous:
|
case authTypeAnonymous:
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
||||||
if s3Error := enforceBucketPolicy("s3:GetObject", bucket, r.URL); s3Error != ErrNone {
|
if s3Error := enforceBucketPolicy("s3:GetObject", bucket, r.URL); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||||
return
|
return
|
||||||
@ -275,7 +293,7 @@ func (api objectStorageAPI) HeadObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
case BucketNotFound:
|
case BucketNotFound:
|
||||||
writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
|
writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
|
||||||
case ObjectNotFound:
|
case ObjectNotFound:
|
||||||
writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
|
writeErrorResponse(w, r, errAllowableObjectNotFound(bucket, r), r.URL.Path)
|
||||||
case ObjectNameInvalid:
|
case ObjectNameInvalid:
|
||||||
writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
|
writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
|
||||||
default:
|
default:
|
||||||
@ -317,8 +335,8 @@ func (api objectStorageAPI) CopyObjectHandler(w http.ResponseWriter, r *http.Req
|
|||||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
||||||
return
|
return
|
||||||
case authTypeAnonymous:
|
case authTypeAnonymous:
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
||||||
if s3Error := enforceBucketPolicy("s3:GetBucketLocation", bucket, r.URL); s3Error != ErrNone {
|
if s3Error := enforceBucketPolicy("s3:PutObject", bucket, r.URL); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -594,7 +612,7 @@ func (api objectStorageAPI) PutObjectHandler(w http.ResponseWriter, r *http.Requ
|
|||||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
||||||
return
|
return
|
||||||
case authTypeAnonymous:
|
case authTypeAnonymous:
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
||||||
if s3Error := enforceBucketPolicy("s3:PutObject", bucket, r.URL); s3Error != ErrNone {
|
if s3Error := enforceBucketPolicy("s3:PutObject", bucket, r.URL); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||||
return
|
return
|
||||||
@ -1053,7 +1071,7 @@ func (api objectStorageAPI) DeleteObjectHandler(w http.ResponseWriter, r *http.R
|
|||||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
||||||
return
|
return
|
||||||
case authTypeAnonymous:
|
case authTypeAnonymous:
|
||||||
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
||||||
if s3Error := enforceBucketPolicy("s3:DeleteObject", bucket, r.URL); s3Error != ErrNone {
|
if s3Error := enforceBucketPolicy("s3:DeleteObject", bucket, r.URL); s3Error != ErrNone {
|
||||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user