-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove default port from host when calculating signature #1618
Conversation
Thanks for creating this PR @s12v. I'm looking into the v4 signing spec to verify that this will not go against any of the v4 specification. |
From the V4 signing specification and test suite i'm not seeing any mention of excluding port from the Host header when computing the signature's canonical string. And per the HTTP RFC the port should be included in the header if its non standard. I'm curious if the failure you're seeing because the a "standard" port of 443 (TLS) is being included in the hostname. |
Related to aws/aws-cli#2883 |
@jasdel, makes sense, thanks for looking into it. |
I changed the code quite a bit and moved tests to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for updating this PR! Stripping off the port conditionally looks good. Just a couple comments about checking if the request value is not nil. And if you ran into situations where this was possible.
aws/signer/v4/v4.go
Outdated
@@ -696,6 +698,81 @@ func (ctx *signingCtx) removePresign() { | |||
ctx.Query.Del("X-Amz-SignedHeaders") | |||
} | |||
|
|||
// Set ctx.Request.Host to host:port for non-standard ports, and to host for explicit standart ports | |||
func (ctx *signingCtx) sanitizeHost() { | |||
if ctx.Request == nil || ctx.Request.URL == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you run into situations where the ctx.Request
value was nil? I think this value is required for the signer to function. In that case i think it would be better to fail loudly instead of silently bypass the nil value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jasdel, I assume it's always set, but I don't know :) Removing the check.
What do you think about ctx.Request.URL
? Should be also always set?
aws/signer/v4/v4.go
Outdated
|
||
// Returns host without port number | ||
func hostname(req *http.Request) string { | ||
if req == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question as above in sanitizeHost
with nil request value.
aws/signer/v4/v4.go
Outdated
return aws.URLHostname(req.URL) | ||
} | ||
|
||
// Copy of url.stripPort() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you update this to mention directly that this was copied for the Go standard library url
package. Would also be also to include the go version too.
aws/signer/v4/v4.go
Outdated
return hostport[:colon] | ||
} | ||
|
||
// Copy of url.portOnly() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto as above
@jasdel, changed. I'm thinking about one more thing: current implementation modifies Please check the next commit to see what I mean. |
I was thinking about this as well. I think the original request must be modified because if the HTTP request sent doesn't use the exact https://play.golang.org/p/Z7opUaTA-F If the Go HTTP client doesn't automatically strip off the "standard" port form the Host header I think this needs to be performed by the SDK. Maybe a better place for this logic would be when the request is created instead of the signer. The signer wouldn't need any special logic if the Host value on the HTTPRequest is already formatted "correctly". |
I think it will not fail (at least it was working for me with AWS ES). Probably, on the receiving side default port is removed before signing. However, it's not explicitly documented anywhere, and maybe it even works differently for different services... no idea. But I agree, that on the other hand, it's better to have signature and host header consistent.
Not sure, the signer accepts |
Thanks for the update @s12v I think with ES you're right the port is probably being removed automatically server side before signature verification. We probably cannot rely on this for all services though. I've heard mentions about standard port in host header causing failures for some services. Thanks a lot for taking the time and putting together this PR by the way!
Good point. This logic would be required in the signer anyways to handle the case a user uses the signer directly with a |
To Resolve this how about we move the For the use case where a user manually calls I think this would allow the logic to be performed in both request building, and ensure the Host header is constructed correctly for anonymous requests, (aka unsigned). |
@jasdel, sounds good, moved to |
Thanks for putting this PR together @s12v. the change looks good. I'll go ahead and merge this in. It will be tagged in our next release. |
@jasdel, it seems the issue with default ports exists in aws-sdk-go-v2, do you have any plans to move the code there? |
Thanks for letting us know about this issue in the v2 SDK @s12v. Would you mind creating a issue in the v2 for this. We'll get that issue ported over. |
Solves #1537
Stumbled upon this issue when working on elasticsearch signatures (elastic/beats#5466). Default elasticsearch port is 9200, I had to include "non-standart" 443 to hostname, and then it calculates wrong signature.