Add whitelist hosts and sensitive headers
This commit is contained in:
@@ -1227,6 +1227,15 @@ span all services and supersede any other route specification.
|
||||
This means that all calls such as "/myusers/101" will be forwarded to "/101" on the "users" service.
|
||||
But calls including "/admin/" will not resolve.
|
||||
|
||||
=== Sensitive Headers
|
||||
|
||||
It's OK to share headers between services in the same system, but you
|
||||
probably don't want sensitive headers leaking downstream into external
|
||||
servers. Thus if you use an explicit URL in a route configuration (as
|
||||
opposed to a service id), then you can also specify a list of
|
||||
sensitive headers and a whitelist of host patterns to not receive
|
||||
those headers.
|
||||
|
||||
=== Strangulation Patterns and Local Forwards
|
||||
|
||||
A common pattern when migrating an existing application or API is to
|
||||
|
||||
@@ -19,8 +19,10 @@ package org.springframework.cloud.netflix.zuul.filters;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -37,6 +39,7 @@ import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
@@ -65,8 +68,20 @@ public class ProxyRequestHelper {
|
||||
|
||||
private Set<String> ignoredHeaders = new LinkedHashSet<>();
|
||||
|
||||
private Set<String> sensitiveHeaders = new LinkedHashSet<>();
|
||||
|
||||
private Set<String> whitelistHosts = new LinkedHashSet<>();
|
||||
|
||||
public void setWhitelistHosts(Set<String> whitelistHosts) {
|
||||
this.whitelistHosts.addAll(whitelistHosts);
|
||||
}
|
||||
|
||||
public void setSensitiveHeaders(Set<String> sensitiveHeaders) {
|
||||
this.sensitiveHeaders.addAll(sensitiveHeaders);
|
||||
}
|
||||
|
||||
public void setIgnoredHeaders(Set<String> ignoredHeaders) {
|
||||
this.ignoredHeaders = ignoredHeaders;
|
||||
this.ignoredHeaders.addAll(ignoredHeaders);
|
||||
}
|
||||
|
||||
public void setTraces(TraceRepository traces) {
|
||||
@@ -182,11 +197,28 @@ public class ProxyRequestHelper {
|
||||
for (String name : this.ignoredHeaders) {
|
||||
set.add(name.toLowerCase());
|
||||
}
|
||||
for (String name : getSensitiveHeaders(ctx)) {
|
||||
set.add(name.toLowerCase());
|
||||
}
|
||||
for (String name : names) {
|
||||
set.add(name.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<String> getSensitiveHeaders(RequestContext ctx) {
|
||||
URL uri = ctx.getRouteHost();
|
||||
if (uri == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
String host;
|
||||
host = uri.getHost();
|
||||
if (PatternMatchUtils.simpleMatch(this.whitelistHosts.toArray(new String[0]),
|
||||
host)) {
|
||||
return this.sensitiveHeaders;
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
public boolean isIncludedHeader(String headerName) {
|
||||
String name = headerName.toLowerCase();
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
|
||||
@@ -66,6 +66,8 @@ public class ZuulProperties {
|
||||
|
||||
private Set<String> ignoredHeaders = new LinkedHashSet<>();
|
||||
|
||||
private Sensitive sensitive = new Sensitive();
|
||||
|
||||
private String servletPath = "/zuul";
|
||||
|
||||
private boolean ignoreLocalService = true;
|
||||
@@ -103,6 +105,21 @@ public class ZuulProperties {
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class Sensitive {
|
||||
/**
|
||||
* Headers that are considered sensitive, and not passed on through a proxy.
|
||||
*/
|
||||
private Set<String> headers = new LinkedHashSet<>(Arrays.asList("Cookie"));
|
||||
/**
|
||||
* Hostname (patterns) that are considered safe and can receive sensitive headers
|
||||
* when a route is specified as a URL.
|
||||
*/
|
||||
private Set<String> whitelist = new LinkedHashSet<>(Arrays.asList("localhost"));
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
|
||||
@@ -209,9 +209,10 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
|
||||
.build();
|
||||
|
||||
this.connectionManager = new PoolingHttpClientConnectionManager(registry);
|
||||
this.connectionManager.setMaxTotal(hostProperties.getMaxTotalConnections());
|
||||
this.connectionManager
|
||||
.setDefaultMaxPerRoute(hostProperties.getMaxPerRouteConnections());
|
||||
.setMaxTotal(this.hostProperties.getMaxTotalConnections());
|
||||
this.connectionManager.setDefaultMaxPerRoute(
|
||||
this.hostProperties.getMaxPerRouteConnections());
|
||||
return this.connectionManager;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
package org.springframework.cloud.netflix.zuul.filters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -28,7 +27,6 @@ import org.mockito.Mock;
|
||||
import org.springframework.boot.actuate.trace.InMemoryTraceRepository;
|
||||
import org.springframework.boot.actuate.trace.Trace;
|
||||
import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.boot.autoconfigure.web.ResourceProperties;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
@@ -163,7 +161,7 @@ public class ProxyRequestHelperTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getQueryString(){
|
||||
public void getQueryString() {
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add("a", "1234");
|
||||
params.add("b", "5678");
|
||||
@@ -174,7 +172,7 @@ public class ProxyRequestHelperTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getQueryStringWithEmptyParam(){
|
||||
public void getQueryStringWithEmptyParam() {
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add("wsdl", "");
|
||||
|
||||
@@ -182,4 +180,36 @@ public class ProxyRequestHelperTests {
|
||||
|
||||
assertThat(queryString, is("?wsdl"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoreSensitiveHeadersMatchingHost() throws Exception {
|
||||
ProxyRequestHelper helper = new ProxyRequestHelper();
|
||||
helper.setSensitiveHeaders(Collections.singleton("Cookie"));
|
||||
helper.setWhitelistHosts(Collections.singleton("*"));
|
||||
RequestContext context = RequestContext.getCurrentContext();
|
||||
context.setRouteHost(new URL("http://example.com"));
|
||||
helper.addIgnoredHeaders();
|
||||
assertThat(helper.isIncludedHeader("Cookie"), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoreSensitiveHeadersNotMatching() throws Exception {
|
||||
ProxyRequestHelper helper = new ProxyRequestHelper();
|
||||
helper.setSensitiveHeaders(Collections.singleton("Cookie"));
|
||||
helper.setWhitelistHosts(Collections.singleton("foo.com"));
|
||||
RequestContext context = RequestContext.getCurrentContext();
|
||||
context.setRouteHost(new URL("http://example.com"));
|
||||
helper.addIgnoredHeaders();
|
||||
assertThat(helper.isIncludedHeader("Cookie"), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoreSensitiveHeadersWhenNoRoute() throws Exception {
|
||||
ProxyRequestHelper helper = new ProxyRequestHelper();
|
||||
helper.setSensitiveHeaders(Collections.singleton("Cookie"));
|
||||
helper.setWhitelistHosts(Collections.singleton("foo.com"));
|
||||
RequestContext context = RequestContext.getCurrentContext();
|
||||
helper.addIgnoredHeaders();
|
||||
assertThat(helper.isIncludedHeader("Cookie"), is(true));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user