Jhipster微服务:Zuul代理访问控制:在端点上过滤未经授权的访问

时间:2019-02-20 23:05:08

标签: spring spring-boot jhipster netflix-zuul

我有一组Jhipster微服务,领事和一个使用Keycloak / OAuth2SSO进行身份验证的网关(我们将其称为Gateway1)。 我想启用多个网关(每个网关服务单独的应用程序),并具有对现有网关(Gateway1)的其他网关(Gateway2,Gateway3等)代理身份验证请求。

我尝试将以下路由添加到Gateway1以处理此问题;

zuul: # those values must be configured depending on the application specific needs
sensitive-headers: Cookie,Set-Cookie #see https://github.com/spring-cloud/spring-cloud-netflix/issues/3126
host:
    max-total-connections: 1000
    max-per-route-connections: 100
semaphore:
    max-semaphores: 500
ignoredServices: 'consul, Gateway1' # Prevent Consul and the "Gateway1" app itself from having a Zuul route automatically created for them
routes:
   Gateway1-uaa:
      path: /api/account/**
      serviceId: Gateway1
      sensitive-headers:

将此路由添加到Gateway1后,在进行身份验证后会收到以下错误消息:

  

访问控制:在端点/ api / account上过滤未经授权的访问

当我点击/ api / authenticate时,它将返回我的用户。所以我怀疑通过令牌传递令牌是一个问题吗?

我尝试设置以下内容失败

  • 对*,
  • 的无用服务
  • 敏感标头为空,
  • 忽略安全头为假。
  • 禁用csrf添加.permitAll
  • 到api /帐户路由和api / **

对为什么这可能不起作用有任何想法吗?

更新

我发现我的项目中的AccessControl类抛出了错误(该错误是Jhipster生成的项目,因此不熟悉所有代码)。

路由用于api /帐户/ **,而调用用于api /帐户。 在过滤器中,检查是否应从授权列表中过滤端点并具有以下代码;

          // If this route correspond to the current request URI
        // We do a substring to remove the "**" at the end of the route URL
        if (requestUri.startsWith(serviceUrl.substring(0, serviceUrl.length() - 3))) {
            return !isAuthorizedRequest(serviceUrl, serviceName, requestUri);
        }

当字符串完全匹配(api / account与api / account)时,requestUri.startsWith返回false。我假设它在末尾期望/。 我将不得不返回并使用api / account / *进行测试,以查看该代码是否可以按预期工作。

现在我将其修改为3个空格,但现在似乎在进行单个api /帐户调用时反复DDoSing服务-

com.netflix.zuul.exception.ZuulException: Filter threw Exception
    at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:227)
    at com.netflix.zuul.FilterProcessor.runFilters(FilterProcessor.java:157)
    at com.netflix.zuul.FilterProcessor.error(FilterProcessor.java:105)
    at com.netflix.zuul.ZuulRunner.error(ZuulRunner.java:112)
    at com.netflix.zuul.http.ZuulServlet.error(ZuulServlet.java:145)
    at com.netflix.zuul.http.ZuulServlet.service(ZuulServlet.java:83)
    at org.springframework.web.servlet.mvc.ServletWrappingController.handleRequestInternal(ServletWrappingController.java:165)
    at org.springframework.cloud.netflix.zuul.web.ZuulController.handleRequest(ZuulController.java:44)
    at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:52)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:873)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:858)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
    at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at com.st.aperture.gateway.config.SimpleCORSFilter.doFilter(SimpleCORSFilter.java:41)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:117)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:106)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at com.st.aperture.gateway.config.OAuth2Configuration$1.doFilterInternal(OAuth2Configuration.java:55)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:65)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:336)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.reflect.UndeclaredThrowableException: null
    at org.springframework.util.ReflectionUtils.rethrowRuntimeException(ReflectionUtils.java:354)
    at org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter.run(SendErrorFilter.java:99)
    at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:117)
    at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:193)
    ... 119 common frames omitted
Caused by: java.io.IOException: An established connection was aborted by the software in your host machine
    at sun.nio.ch.SocketDispatcher.write0(Native Method)
    at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51)
    at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
    at sun.nio.ch.IOUtil.write(IOUtil.java:65)
    at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471)
    at org.xnio.nio.NioSocketConduit.write(NioSocketConduit.java:164)
    at io.undertow.server.protocol.http.HttpResponseConduit.write(HttpResponseConduit.java:609)
    at io.undertow.conduits.ChunkedStreamSinkConduit.flush(ChunkedStreamSinkConduit.java:269)
    at org.xnio.conduits.ConduitStreamSinkChannel.flush(ConduitStreamSinkChannel.java:162)
    at io.undertow.channels.DetachableStreamSinkChannel.flush(DetachableStreamSinkChannel.java:119)
    at org.xnio.channels.Channels.flushBlocking(Channels.java:63)
    at io.undertow.servlet.spec.ServletOutputStreamImpl.close(ServletOutputStreamImpl.java:617)
    at org.springframework.security.web.util.OnCommittedResponseWrapper$SaveContextServletOutputStream.close(OnCommittedResponseWrapper.java:520)
    at io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:236)
    at io.undertow.servlet.spec.RequestDispatcherImpl.forwardImplSetup(RequestDispatcherImpl.java:147)
    at io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:111)
    at org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequestDispatcher.forward(HeaderWriterFilter.java:143)
    at org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter.run(SendErrorFilter.java:94)
    ... 121 common frames omitted

我想知道是否存在重定向回api /帐户或类似路径的重定向...搜索继续!

2 个答案:

答案 0 :(得分:0)

所以我在这个过程中学到了一些非常困难的教训-

首先-我将针对如上所述的Jhipster accessControl过滤器提出一个错误,因为它在已经触发的路由上添加了另一层路由验证并过滤了良好的路由。如果您正在获取访问控制:端点/ api / account 上经过过滤的未经授权的访问,就别无所求-只需将其从网关配置中删除即可。

第二个-我认为在我的设置中或者只是在zuul中存在一个问题,如果目标路径/结果路径不正确-您会在堆栈上传递500错误而不是404。这可能是crsf,但这是错误的错误处理。 因此,如果您看到“服务器终止连接”或“ hystrix读取超时”,则可能确实是错误的目标网址。

第三-如果API遵循完全相同的命名约定,则很容易建立循环和DDoS您自己的代理。 例如,我打了gateway2 / api / account并希望将其路由到gateway1 / api / account,所以我设置了 路线: 路径:api /帐户 服务:gateway1 条形前缀:false

这很好用...但是请求返回gateway1 / api / account并重定向到AGAIN ..和AGAIN ..和AGAIN,直到您使电路跳闸。

我最终在gateway1上更改了API的名称,并且效果很好。

答案 1 :(得分:0)

所以-感到烦恼的是,我可能会通过重命名API来破坏某些内容,并且Zuul在管理前缀方面很差,所以我决定最好的办法是处理一个自定义过滤器;

  1. 删除前缀,即路径之前与路径不匹配的任何内容(例如,将gw / api / account发送到我的路线 / api / account不应发送service1 / gw / api / account。请注意,我的实现不支持/ api / ** / account /)之类的复杂匹配模式
  2. 不路由“本地”请求,即,如果请求中没有服务名称,则仅转发请求(例如,呼叫 网关上的api / account,不应触发我的/ api / account 网关路由。而且绝对不是kthx Zuul的50倍。不苦。)
  3. 尽管有上述规则,但允许其他请求自由路由

导入静态org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.FORWARD_TO_KEY;

import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.netflix.zuul.context.RequestContext;
import com.st.aperture.gateway.gateway.filters.RequestRewriter;
import com.netflix.zuul.ZuulFilter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;

public class SimplePreFilter extends ZuulFilter {

    private static Logger log = LoggerFactory.getLogger(SimplePreFilter.class);
    private ZuulProperties properties;
    private Map<String, ZuulRoute> routes;
    private DiscoveryClient discovery;

    public SimplePreFilter(ZuulProperties properties, DiscoveryClient discovery) {
        this.properties = properties;
        this.discovery = discovery;
        this.routes = this.properties.getRoutes();
    }

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {

        return true;
    }

    @Override
    public Object run() {

        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String requestUrl = ctx.getRequest().getRequestURI().toString();

        List<String> services = discovery.getServices();

        String modifiedPath = "";
        Boolean internalService = true;

        for (String service : services) {
            if (requestUrl.contains(service + "/")) {
                // if the url contains a service name, then its not local
                internalService = false;
                break;
            }
        }

        // The routes are the statically configured routes
        for (ZuulRoute zr : routes.values()) {
            // This will break support for wildcards in the middle of paths, consider improving
            String simpleRoute = zr.getPath().replace("/**", "");
            if (requestUrl.contains(simpleRoute) && zr.isStripPrefix() == false) {
                modifiedPath = requestUrl.substring(requestUrl.indexOf(simpleRoute.substring(0, 5)));
                break;
            }
        }

        if (internalService) {
            ctx.put(FORWARD_TO_KEY, requestUrl);
            log.debug("ROUTING: Local Request - " + requestUrl);
        } else if (modifiedPath != "") {
            RequestRewriter requestRewriter = new RequestRewriter(request);
            requestRewriter.setRequestURI(modifiedPath);
            ctx.setRequest(requestRewriter);
            log.debug("ROUTING: Foreign Request: " + requestUrl + " route prefix stripped to: " + modifiedPath);
        } else {
            log.debug("ROUTING: Foreign Request: " + requestUrl);
        }

        return null;
    }

}