Skip to content
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

ProxyExchange - ability to override sensitive headers #1800

Closed
ilyasjaan opened this issue Jun 26, 2020 · 16 comments
Closed

ProxyExchange - ability to override sensitive headers #1800

ilyasjaan opened this issue Jun 26, 2020 · 16 comments

Comments

@ilyasjaan
Copy link

Problem
If we use webmvc version of gateway we have ProxyExchange object that forwards the requests to downstream. It removes two headers "cookie" and "authorization" as default. If we compare this behavior with simple yaml routes config - nothing is removed and all sent to downstream as-is.
I have a downstream service that needs basic authentication, and intentionally I don't want (in this case) to do anything in gateway and trying to simply delegate request to downstream. But I want to use webmvc way of gateway because I need to manipulate a bit on response.

Describe the solution you'd like
At the moment ProxyExchange.DEFAULT_SENSITIVES is public. That means you do expect people to play with it. I made it work by removing the "authorization" from the map.
But it looks ugly. public static access outside (not nice).

I was expecting ProxyExchange defaults to be overridden by config. Like ZUUL we can set our own defined list of sensitive headers. Spring Cloud Gateway just adds sensitive headers from config on top of existing defaults.

Describe alternatives you've considered
I have used public access...
But thinking to configure other way and use filters to play with response.

Additional context
IMO - Both ways we should have same behavior. If there is a need to remove default sensitives then why just ProxyExchange?

@spencergibb
Copy link
Member

There is also ProxyExchange.sensitive().

@ilyasjaan
Copy link
Author

Yes but that is additive on top of defaults.
Using this I cannot say that "authorization" is not sensitive... because that is default sensitive and it will stay sensitive unless I change the default static sensitive list by using public access.

@spencergibb
Copy link
Member

spring.cloud.gateway.proxy.sensitive

@ilyasjaan
Copy link
Author

I looked at that... it is also using the same method underneath.
ProxyExchange.sensitive
Technically same as calling that method to add more sensitive headers on top of defaults.

I also thought this property should be to define your list of sensitive headers... but this is to add your list of sensitives on top of defaults.

I might be wrong but I can check again the source code of gateway that handles this property...

@mplain
Copy link

mplain commented Aug 19, 2020

Bumping this issue

ProxyExchange is created with "sensitive" set to DEFAULT_SENSITIVE (cookie and auth), then there is only a method to add more headers to the list, but no way to remove any

@ilyasjaan
Copy link
Author

This is exactly I explained to start with.

There should be a way to define own set of sensitive headers like ZUUL we have.

@vadimkim
Copy link

vadimkim commented Oct 6, 2020

I used proxy with spring-cloud-gateway-mvc for a long time and decided to refactor it to spring-cloud-gateway-webflux. The first thing that stops working is "sensitive" headers manipulation. If compare the source code of ProxyExchange from "mvc" and "webflux" packages the reason can be found quickly.

Working "MVC" class has:

public class ProxyExchange<T> {
    public static Set<String> DEFAULT_SENSITIVE = new HashSet(Arrays.asList("cookie", "authorization"));
     ...
    private Set<String> sensitive;
    ...

    public ProxyExchange(RestTemplate rest, NativeWebRequest webRequest, ModelAndViewContainer mavContainer, WebDataBinderFactory binderFactory, Type type) {
        this.responseType = type;
        this.rest = rest;
        this.webRequest = webRequest;
        this.mavContainer = mavContainer;
        this.binderFactory = binderFactory;
        this.delegate = new RequestResponseBodyMethodProcessor(rest.getMessageConverters());
    }

Non-working "webflux" code is:

public class ProxyExchange<T> {
    public static Set<String> DEFAULT_SENSITIVE = new HashSet(Arrays.asList("cookie", "authorization"));
    ...
    private Set<String> sensitive;
    ...

    public ProxyExchange(WebClient rest, ServerWebExchange exchange, BindingContext bindingContext, Type type) {
        this.exchange = exchange;
        this.bindingContext = bindingContext;
        this.responseType = type;
        this.rest = rest;
        this.sensitive = new HashSet(DEFAULT_SENSITIVE.size());
        this.sensitive.addAll(DEFAULT_SENSITIVE);
        this.httpMethod = exchange.getRequest().getMethod();
    }

As you can see here default sensitive list is created in the constructor, thus hard-coded and can only be expanded later by adding more headers. You are not able to remove "cookie" or "authentication" from the default list.
In compare to working "mvc" proxy headers are initialized later at the builder:

    private BodyBuilder headers(BodyBuilder builder) {
        Set<String> sensitive = this.sensitive;
        if (sensitive == null) {
            sensitive = DEFAULT_SENSITIVE;
        }

       ...

        return builder;
    }

thus if user doesn't provide sensitive header list - the default ("cookie" and "authorization") is used. If user wants to customize sensitive list he is able to do it. For example by setting spring.cloud.gateway.proxy.sensitive application configuration property
Webflux proxy has similar piece of code to manipulate sensitive headers list:

 public ProxyExchange<T> sensitive(String... names) {
        if (this.sensitive == null) {
            this.sensitive = new HashSet();
        }

}

... but since sensitive variable is already initialized in the constructor and is never null this predicate never works.

I think this is a bug in PoxyExchange class at org.springframework.cloud.gateway.webflux package. User must have control of the proxy headers. My use case - is proxy for user web session that is implemented using JWT token on backend. I have to "convert" one authentication to another and must replace "cookie" with new "authentication" and pass Bearer token down to web-service. Unfortunately it is not possible with ProxyExchange and Webflux.
Quick workaround at the moment is to use ProxyExchange from MVC package.

@ilyasjaan
Copy link
Author

Exactly, what I raised to start with. I think I am going to contribute to fix that... More often people finding same issue now, but this is still open ticket.

@vadimkim
Copy link

vadimkim commented Oct 6, 2020

Thank you, @ilyasjaan for contribution. Let me know if I can help. I am going to fix it locally, but will be waiting for official release to make it available at production

@vadimkim
Copy link

vadimkim commented Dec 9, 2020

Hello. When this issue be merged with main code? I don't understand where it jammed.

@srikanth88infy
Copy link

Any updates on this request? I see that the change is still not merged.

@spencergibb spencergibb added this to To do in 2020.0.4 via automation Jun 16, 2021
@spencergibb spencergibb added this to To do in Hoxton.SR12 via automation Jun 16, 2021
@spencergibb spencergibb moved this from To do to In progress in Hoxton.SR12 Jun 17, 2021
@spencergibb spencergibb removed this from In progress in Hoxton.SR12 Jul 7, 2021
@Jerry29
Copy link

Jerry29 commented Jul 19, 2021

Any update on this issue ? @spencergibb

I am using spring-cloud gateway as reverse proxy and getting the following error for websocket requests . Seems like a similar issue. While debugging the packets observed that Authentication header was missing.

io.netty.handler.codec.http.websocketx.WebSocketClientHandshakeException: Invalid handshake response getStatus: 401 Unauthorized

@vadimkim
Copy link

I suggest you to copy this part of code from MVC ProxyExchange class. It is only couple rows of code. There is no point to wait for release of this this bugfix

@GabrielBB
Copy link

wow, this is not yet fixed

@vadimkim
Copy link

vadimkim commented Sep 4, 2021

@GabrielBB , it has probably too low priority or too simple fix :)

@ryanjbaxter ryanjbaxter removed this from To do in 2020.0.4 Sep 28, 2021
@ryanjbaxter ryanjbaxter added this to To do in 2020.0.5 via automation Sep 28, 2021
@spencergibb spencergibb moved this from To do to In progress in 2020.0.5 Nov 1, 2021
@spencergibb spencergibb added this to To do in 2021.0.0-RC1 via automation Nov 1, 2021
@spencergibb spencergibb added this to the 3.0.5 milestone Nov 1, 2021
2020.0.5 automation moved this from In progress to Done Nov 1, 2021
2021.0.0-RC1 automation moved this from To do to Done Nov 1, 2021
@PRySvI
Copy link

PRySvI commented Feb 27, 2023

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
2020.0.5
  
Done
2021.0.0-RC1
  
Done
Development

Successfully merging a pull request may close this issue.

9 participants