-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Forward with query duplicates parameter values #2074
Comments
What version of Jetty are you running ? Can you add a test case to |
I'm using spring boot 1.5.6.RELEASE which is using jetty 9.4.6.v20170531 On the test you mentioned, the forwarded url has the same parameter as as the original request but with another value ... not sure why this would be the case, but ok ... In my case, the forward is not changing any values, I'm simply removing the language part of the url so it can be handled by the controllers as if it wasn't there ... so the parameters are the same and so are their values |
Changing the test to use the same query string in the forward results in the same behavior (i.e. the query string is replaced in the forward, not merged). |
The problem is that on line 164 of that test, when it does
the String[] paramValues = request.getParameterValues(name);
if (paramValues != null) {
arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
} and that makes all values to be returned |
Ah, good point about index 0. I'll review the test and the behavior and report back. |
Do you still need more info on this? |
+ Adding testcases that replicate the behavior reported. Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
@janbartel @gregw I've been able to replicate the issues reported here. See test cases in commit 7022220 Currently, the fault lies in Take this testcase ... This will result in a new "merged" MultiMap with a single entry "id", but with 2 values ["123", "123"] (The assertion on line 577 fails) We either need to make MultiMap.addAllValues() not add a value if it's not unique (which is what I'm leaning towards, as Or we make |
One way to look at this is from the URI point of view. Given that the original URI is
The decision here needs to be thoughtful as to not trip over HPP (HTTP Parameter Pollution) security concerns. |
I'm not 100% sure.... but I do recall that it is intended behaviour that a parameter that is both in the original URI and in the forward URI has both values! So I do think it is the expected behaviour. |
original URI resulting URI should be |
The Servlet Spec 3.1 Final Section 9.1.1 seems to indicate that there should be no merging. If we change this in |
This means that the RequestDispatcher shouldn't be using |
It's what I imagined as desirable ... but if what @joakime described from the spec is correct, that is the behaviour |
My recollection is that the query merge behaviour was driven by TCK test suite. As we are currently in the process of rerunning the TCK, let's hold action on this one until we can check it's results. @fripoli I'm 99% sure that the resulting URI for your example should be |
After reading that OWASP link for HTTP Parameter Pollution, I'm not sure that merging for RequestDispatcher is the right thing anymore (from a security and behavior point of view). Also, in the use case that opened this issue, I think we are still in violation of Section 9.1.1 of the spec.
To me, that means if the parameter name exists in the RequestDispatcher forward call, that parameter replace/overwrites the values of the original URI. not merging/adding values. |
I'm not sure how this relates to a HPP attack vector? An application that a)trusts user input; b) does not validate user input; c) does not correctly handle multiple vs single parameters; is going to be HPP vulnerable regardless of the use of forwarding. Now forwarding may well be one way that an application mixes in trusted parameters with user supplied parameters, but it's not the only way. In short, I think that HPP is a framework/application issue and that there is little that the container can do - other than check for correct adherence to RFCs and standards for formatting and escaping of URIs and form content. Now that is not to say that we should not revisit the parameter merging we are doing here to check we are interpreting the spec correctly, I just don't see it as a security issue. |
@joakime but also see Servlet Spec section 9.4.1 Query String:
There is no description of what "aggregation" means, but could be taken to imply that existing query params are merged with any query params specified to the request dispatcher, as jetty is doing. The section that you cite, 9.1.1 could be taken to mean that if the query param is present in the request dispatcher call, it should override any existing param of the same name in the calling request. |
Just to follow up and be clear: the query string that is passed to the forwarded-to servlet does not contain duplicate entries of the same name - jetty correctly gives precedence to query params present in the call to the request dispatcher; the param map from within the forwarded-to servlet does contain multiple values for the same name, but the value provided to the request dispatcher will always be at index 0. In other words, given an original request to "/one?id=123", and request dispatch forward to "/two?id=123", from within the forwarded-to servlet we have:
The above behaviour has been true at least as far back as jetty-8.2, I haven't looked any further back. I'm not clear whether the OP is arguing that request.getParameterValues() should never return multiple values from within the forward-to servlet (ie even if the values are different), or only never return duplicate values? |
Hey, @joakime! Thank you for working on this! I also faced the same problem with the async support in spring framework, so I created a minimal reproducer for the issue: https://github.com/SerCeMan/jettyredirect. Returning a $ curl http://localhost:8070/page1?str=test
params: test,test Is there anything I can do to help to move this issue forward? As far as I can understand from the comments, there is an ambiguity in the spec, please let me know if I should file a bug in the spring project instead. |
I think that the method |
Nope, query parameters are not appended, they are merged. Values for the same key are appended, but the keys are merged, so |
@olamy are there any tck tests for the handling of query params for forwards an includes?? |
@janbartel I cannot see any dedicated to this particular case. |
This breaking change may or may not follow spec, but for me this means reverting to an older version or in the longer term replacing with a different server to keep legacy code running. I suggest you fix according to least astonishment asap and ignore vague spec wordings. |
@highfestiva what older Jetty version shows a behavior that's good for you? |
I cannot find an issue filed at https://github.com/eclipse-ee4j/servlet-api asking for clarification on this. So I asked jakartaee/servlet#308 |
@sbordet @janbartel @joakime @fripoli While working on #4721 I have noticed something very wrong with our merging of query parameters! When we merge the actual parameter maps during a forward we keep all parameter values with: But when we merge the query strings, we remove the values from the old string that are named in the new string: So whatever is the correct behaviour, somehow we are doing one for the map and the other for the string, so that cannot be right! |
Servlet specification 9.1.1 says:
So "take precedence over other parameters of the same name" is a little bit vague and could be interpreted either as "are ordered before parameter values of the same name" or "replace parameters of the same name". I'll experiment with #4721 and check against the TCK |
I can only find one TCK test regarding this at https://github.com/eclipse-ee4j/jakartaee-tck/blob/8.0/src/com/sun/ts/tests/servlet/spec/requestdispatcher/URLClient.java#L463-L478
So this suggests that at least for parameters with same name and same value, that they are not duplicated. However, I can't find what document the |
Should probably have this conversation about what the spec intends over at jakartaee/servlet#308 |
@joakime sure, but doing basic research first.
I tried this on various servers and got:
These are all pretty much the same and kind of agree with the strange interpretation of the spec (my panic is subsiding a little). The only difference is that Jetty includes the |
If the forward does not have a query, then all servers keep the original query string in the merge. |
Considering the difference is very minor, I think we should keep 9.4 as is and change in 10 to act like the other servers with regards to the query string (replaced by forward not merged). |
Do not merge the query string itself, only the parameter map. The query string is either the original or replaced by the one from the dispatch. Signed-off-by: Greg Wilkins <gregw@webtide.com>
* Issue #4713 Async dispatch with query. + Preserve the entire URI with query when startAsync(req,res) is used. + merge any query string from dispatch path with either original query or preserved query from forward Signed-off-by: Greg Wilkins <gregw@webtide.com> * Issue #4713 asyncDispatch with query parameters Signed-off-by: Greg Wilkins <gregw@webtide.com> * Issue #2074 Do not merge query strings Do not merge the query string itself, only the parameter map. The query string is either the original or replaced by the one from the dispatch. Signed-off-by: Greg Wilkins <gregw@webtide.com>
I'm using Spring boot with Jetty and Tuckey URL Rewrite.
The URL rewrite is doing a forward including all query parameters that were sent to the original request.
For example
The query parameter map on the request then become a map of
productId
with the value[123,123]
Is that the expected behaviour?
I can see there are some testing around this forward functionality here but none of them covers this case
The text was updated successfully, but these errors were encountered: