mirror of
https://github.com/minio/minio.git
synced 2025-02-27 05:19:16 -05:00
Limit POST form fields and file size + Generic Request Size limiter (#2317)
* Use less memory when receiving a file via multipart * Add generic http request maximum size limiter to secure against malicious clients
This commit is contained in:
parent
7850d17f48
commit
dcc3463e48
@ -347,7 +347,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
||||
return
|
||||
}
|
||||
|
||||
fileBody, fileName, formValues, err := extractHTTPFormValues(reader)
|
||||
fileBody, fileName, formValues, err := extractPostPolicyFormValues(reader)
|
||||
if err != nil {
|
||||
errorIf(err, "Unable to parse form values.")
|
||||
writeErrorResponse(w, r, ErrMalformedPOSTRequest, r.URL.Path)
|
||||
|
@ -39,6 +39,27 @@ func registerHandlers(mux *router.Router, handlerFns ...HandlerFunc) http.Handle
|
||||
return f
|
||||
}
|
||||
|
||||
// Adds limiting body size middleware
|
||||
|
||||
// Set the body size limit to 6 Gb = Maximum object size + other possible data
|
||||
// in the same request
|
||||
const requestMaxBodySize = 1024 * 1024 * 1024 * (5 + 1)
|
||||
|
||||
type requestSizeLimitHandler struct {
|
||||
handler http.Handler
|
||||
maxBodySize int64
|
||||
}
|
||||
|
||||
func setRequestSizeLimitHandler(h http.Handler) http.Handler {
|
||||
return requestSizeLimitHandler{handler: h, maxBodySize: requestMaxBodySize}
|
||||
}
|
||||
|
||||
func (h requestSizeLimitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Restricting read data to a given maximum length
|
||||
r.Body = http.MaxBytesReader(w, r.Body, h.maxBodySize)
|
||||
h.handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// Adds redirect rules for incoming requests.
|
||||
type redirectHandler struct {
|
||||
handler http.Handler
|
||||
|
@ -52,6 +52,12 @@ var (
|
||||
// Add new variable global values here.
|
||||
)
|
||||
|
||||
var (
|
||||
// Limit fields size (except file) to 1Mib since Policy document
|
||||
// can reach that size according to https://aws.amazon.com/articles/1434
|
||||
maxFormFieldSize = int64(1024 * 1024)
|
||||
)
|
||||
|
||||
// global colors.
|
||||
var (
|
||||
colorBlue = color.New(color.FgBlue).SprintfFunc()
|
||||
|
@ -17,7 +17,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
@ -99,12 +98,11 @@ func extractMetadataFromHeader(header http.Header) map[string]string {
|
||||
return metadata
|
||||
}
|
||||
|
||||
func extractHTTPFormValues(reader *multipart.Reader) (io.Reader, string, map[string]string, error) {
|
||||
// Extract form fields and file data from a HTTP POST Policy
|
||||
func extractPostPolicyFormValues(reader *multipart.Reader) (filePart io.Reader, fileName string, formValues map[string]string, err error) {
|
||||
/// HTML Form values
|
||||
formValues := make(map[string]string)
|
||||
filePart := new(bytes.Buffer)
|
||||
fileName := ""
|
||||
var err error
|
||||
formValues = make(map[string]string)
|
||||
fileName = ""
|
||||
for err == nil {
|
||||
var part *multipart.Part
|
||||
part, err = reader.NextPart()
|
||||
@ -112,19 +110,22 @@ func extractHTTPFormValues(reader *multipart.Reader) (io.Reader, string, map[str
|
||||
canonicalFormName := http.CanonicalHeaderKey(part.FormName())
|
||||
if canonicalFormName != "File" {
|
||||
var buffer []byte
|
||||
buffer, err = ioutil.ReadAll(part)
|
||||
limitReader := io.LimitReader(part, maxFormFieldSize+1)
|
||||
buffer, err = ioutil.ReadAll(limitReader)
|
||||
if err != nil {
|
||||
return nil, "", nil, err
|
||||
}
|
||||
if int64(len(buffer)) > maxFormFieldSize {
|
||||
return nil, "", nil, errSizeUnexpected
|
||||
}
|
||||
formValues[canonicalFormName] = string(buffer)
|
||||
} else {
|
||||
if _, err = io.Copy(filePart, part); err != nil {
|
||||
return nil, "", nil, err
|
||||
}
|
||||
filePart = io.LimitReader(part, maxObjectSize)
|
||||
fileName = part.FileName()
|
||||
// As described in S3 spec, we expect file to be the last form field
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return filePart, fileName, formValues, nil
|
||||
|
||||
}
|
||||
|
@ -79,6 +79,8 @@ func configureServerHandler(srvCmdConfig serverCmdConfig) http.Handler {
|
||||
var handlerFns = []HandlerFunc{
|
||||
// Limits the number of concurrent http requests.
|
||||
setRateLimitHandler,
|
||||
// Limits all requests size to a maximum fixed limit
|
||||
setRequestSizeLimitHandler,
|
||||
// Adds 'crossdomain.xml' policy handler to serve legacy flash clients.
|
||||
setCrossDomainPolicy,
|
||||
// Redirect some pre-defined browser request paths to a static location prefix.
|
||||
|
@ -32,3 +32,6 @@ var errInvalidToken = errors.New("Invalid token")
|
||||
|
||||
// If x-amz-content-sha256 header value mismatches with what we calculate.
|
||||
var errContentSHA256Mismatch = errors.New("sha256 mismatch")
|
||||
|
||||
// used when we deal with data larger than expected
|
||||
var errSizeUnexpected = errors.New("data size larger than expected")
|
||||
|
Loading…
x
Reference in New Issue
Block a user