Do not reply on ignoredHeaders for server, rely on SignedHeaders sent as part of Authorization header

master
Harshavardhana 10 years ago
parent 538572ca91
commit 97d4a27c7e
  1. 40
      pkg/donut/signature-v4.go
  2. 3
      pkg/server/api/bucket-handlers.go
  3. 4
      pkg/server/api/generic-handlers.go

@ -102,13 +102,10 @@ func urlEncodeName(name string) (string, error) {
}
// getCanonicalHeaders generate a list of request headers with their values
func (r *Signature) getCanonicalHeaders() string {
func (r *Signature) getCanonicalHeaders(signedHeaders map[string][]string) string {
var headers []string
vals := make(map[string][]string)
for k, vv := range r.Request.Header {
if _, ok := ignoredHeaders[http.CanonicalHeaderKey(k)]; ok {
continue // ignored header
}
for k, vv := range signedHeaders {
headers = append(headers, strings.ToLower(k))
vals[strings.ToLower(k)] = vv
}
@ -137,12 +134,9 @@ func (r *Signature) getCanonicalHeaders() string {
}
// getSignedHeaders generate a string i.e alphabetically sorted, semicolon-separated list of lowercase request header names
func (r *Signature) getSignedHeaders() string {
func (r *Signature) getSignedHeaders(signedHeaders map[string][]string) string {
var headers []string
for k := range r.Request.Header {
if _, ok := ignoredHeaders[http.CanonicalHeaderKey(k)]; ok {
continue // ignored header
}
for k := range signedHeaders {
headers = append(headers, strings.ToLower(k))
}
headers = append(headers, "host")
@ -150,6 +144,22 @@ func (r *Signature) getSignedHeaders() string {
return strings.Join(headers, ";")
}
// extractSignedHeaders extract signed headers from Authorization header
func (r *Signature) extractSignedHeaders() map[string][]string {
authFields := strings.Split(strings.TrimSpace(r.AuthHeader), ",")
extractedHeaders := strings.Split(strings.Split(strings.TrimSpace(authFields[1]), "=")[1], ";")
extractedSignedHeadersMap := make(map[string][]string)
for _, header := range extractedHeaders {
val, ok := r.Request.Header[http.CanonicalHeaderKey(header)]
if !ok {
// if not found continue, we will fail later
continue
}
extractedSignedHeadersMap[header] = val
}
return extractedSignedHeadersMap
}
// getCanonicalRequest generate a canonical request of style
//
// canonicalRequest =
@ -169,9 +179,9 @@ func (r *Signature) getCanonicalRequest() string {
r.Request.Method,
encodedPath,
r.Request.URL.RawQuery,
r.getCanonicalHeaders(),
r.getSignedHeaders(),
r.Request.Header.Get("x-amz-content-sha256"),
r.getCanonicalHeaders(r.extractSignedHeaders()),
r.getSignedHeaders(r.extractSignedHeaders()),
r.Request.Header.Get(http.CanonicalHeaderKey("x-amz-content-sha256")),
}, "\n")
return canonicalRequest
}
@ -214,11 +224,11 @@ func (r *Signature) getSignature(signingKey []byte, stringToSign string) string
// returns true if matches, false other wise if error is not nil then it is always false
func (r *Signature) DoesSignatureMatch(hashedPayload string) (bool, error) {
// set new calulated payload
r.Request.Header.Set("x-amz-content-sha256", hashedPayload)
r.Request.Header.Set("X-Amz-Content-Sha256", hashedPayload)
// Add date if not present
var date string
if date = r.Request.Header.Get("x-amz-date"); date == "" {
if date = r.Request.Header.Get(http.CanonicalHeaderKey("x-amz-date")); date == "" {
if date = r.Request.Header.Get("Date"); date == "" {
return false, iodine.New(MissingDateHeader{}, nil)
}

@ -405,7 +405,8 @@ func (api Minio) HeadBucketHandler(w http.ResponseWriter, req *http.Request) {
case nil:
writeSuccessResponse(w, acceptsContentType)
case donut.SignatureDoesNotMatch:
writeErrorResponse(w, req, SignatureDoesNotMatch, acceptsContentType, req.URL.Path)
error := getErrorCode(SignatureDoesNotMatch)
w.WriteHeader(error.HTTPStatusCode)
case donut.BucketNotFound:
error := getErrorCode(NoSuchBucket)
w.WriteHeader(error.HTTPStatusCode)

@ -45,7 +45,7 @@ const (
)
func parseDate(req *http.Request) (time.Time, error) {
amzDate := req.Header.Get("x-amz-date")
amzDate := req.Header.Get(http.CanonicalHeaderKey("x-amz-date"))
switch {
case amzDate != "":
if _, err := time.Parse(time.RFC1123, amzDate); err == nil {
@ -97,7 +97,7 @@ func (h timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
acceptsContentType := getContentType(r)
// Verify if date headers are set, if not reject the request
if r.Header.Get("Authorization") != "" {
if r.Header.Get("x-amz-date") == "" && r.Header.Get("Date") == "" {
if r.Header.Get(http.CanonicalHeaderKey("x-amz-date")) == "" && r.Header.Get("Date") == "" {
// there is no way to knowing if this is a valid request, could be a attack reject such clients
writeErrorResponse(w, r, RequestTimeTooSkewed, acceptsContentType, r.URL.Path)
return

Loading…
Cancel
Save