fix: avoid unescaping slashes when proxying URLs #1134
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Doing all the path operations on URL.Path means that they're being performed on an unescaped URL. Unfortunately, this URL is not guaranteed to be the directly unescaped version of URL.EscapedPath(); in particular, slashes will be unescaped in URL.Path, e.g. given:
/abc%2Fdef
URL.Path will be:
/abc/def
In these cases, URL.RawPath is also set with the escaped version of the path. However, once URL.Path is modified, URL.RawPath is ignored, and URL.EscapedPath() returns the path-escaped version of URL.Path...which, in this case, is now /abc/def, not the correct /abc%2Fdef.
As a result, when performing any path modifications during proxying (i.e. proxying to an upstream URL with a path component, or applying StripPath), this results in any escaped slashes in the proxied URL being unescaped.
In order to work around this, rewriting operations need to take place on the escaped path, not the unescaped one, and then an intermediate URL can be used to determine the Path and RawPath values to set on the forward URL.
This incurs a small breaking change in that StripPath is now applied to the escaped URL, not the unescaped URL. These semantics arguably make more sense, since StripPath otherwise also cannot distinguish between unencoded slashes within a path segment vs those that are separating path segments, but it's still a breaking change nonetheless.
Checklist
introduces a new feature.
contributing code guidelines.
vulnerability. If this pull request addresses a security vulnerability, I
confirm that I got the approval (please contact
[email protected]) from the maintainers to push
the changes.
works.
Further Comments
I debating trying to preserve the current
strip_path
semantics, but in addition to being unable to distinguish/
and%2F
, it's also just incredibly ugly: I need to put the value of the attribute in a stub URL and parse that to get the escaped path, which also introduces a large amount of weird edge cases that come from quirks in URL parsers.