4

我正在尝试为 Web 应用程序上的某些页面启用 HTTPS。我将 Spring MVC 和 Spring Security 用于部署在 Tomcat 上的 Web 应用程序,并使用 Nginx 作为 tomcat 的代理。

首先,一切正常,无需任何 HTTPS 配置。我生成了一个自签名 SSL 证书并将其安装在 Nginx 上。我没有对 Tomcat 进行任何更改以启用 HTTPS,因为我只想让 Nginx 处理 SSL 终止。这是我对 SSL 的相关 Nginx 配置。

         listen 443;
         server_name 127.0.0.1;
         root /usr/local/server/web/webapps/ROOT;

         ssl on;
         ssl_certificate /usr/local/etc/nginx/ssl/server.crt;
         ssl_certificate_key /usr/local/etc/nginx/ssl/server.key;


         location / {
                    proxy_pass      http://localhost:8080;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header Host $http_host;
            }

我的 SSL 的 Spring 安全配置如下所示:

<http pattern="/static/**" security="none" />
<http pattern="/favicon*" security="none" />

<http use-expressions="true">
    <intercept-url pattern="/login" access="permitAll" requires-channel="https" />
    <intercept-url pattern="/loginprocess" method="POST" requires-channel="https" />
    <intercept-url pattern="/logout" access="isAuthenticated()"/>
    <intercept-url pattern="/**" access="isAuthenticated()" requires-channel="https" />
    <form-login username-parameter="username"
        password-parameter="password" login-page="/login"
        login-processing-url="/loginprocess" default-target-url="/hiring"
        authentication-failure-url="/login?error" always-use-default-target="true" />
    <logout logout-url="/logout" logout-success-url="/login?logout" />
</http>

现在,当我尝试在浏览器上访问登录页面时 -https://localhost/internal/login出现错误 -

此网页有重定向循环

Spring Security 中的日志如下所示:

12:34:55.240 [http-bio-8080-exec-33] DEBUG o.s.security.web.FilterChainProxy - /login at       position 1 of 10 in additional filter chain; firing Filter: 'ChannelProcessingFilter'
12:34:55.240 [http-bio-8080-exec-33] DEBUG o.s.s.web.util.AntPathRequestMatcher - Checking    match of request : '/login'; against '/login'
12:34:55.240 [http-bio-8080-exec-33] DEBUG o.s.s.w.a.c.ChannelProcessingFilter - Request: FilterInvocation: URL: /login; ConfigAttributes: [REQUIRES_SECURE_CHANNEL]
12:34:55.240 [http-bio-8080-exec-33] DEBUG o.s.s.w.a.c.RetryWithHttpsEntryPoint - Redirecting to: https://localhost/internal/login
12:34:55.241 [http-bio-8080-exec-33] DEBUG o.s.s.web.DefaultRedirectStrategy - Redirecting to 'https://localhost/internal/login'

我尝试使用 requires-channel 一段时间,但并没有真正奏效。任何帮助/指针都会很棒。

更新

我尝试使用以下配置,重定向循环错误不再存在。但是,这些日志的身份验证失败 -

03:29:28.603 [http-bio-8080-exec-19] DEBUG o.s.s.w.a.c.ChannelProcessingFilter - Request:  FilterInvocation: URL: /loginprocess; ConfigAttributes: [REQUIRES_SECURE_CHANNEL]
03:29:28.603 [http-bio-8080-exec-19] DEBUG o.s.s.w.a.c.RetryWithHttpsEntryPoint - Redirecting to: https://localhost/internal/loginprocess
03:29:28.603 [http-bio-8080-exec-19] DEBUG o.s.s.web.DefaultRedirectStrategy - Redirecting to 'https://localhost/internal/loginprocess'

03:29:28.609 [http-bio-8080-exec-11] DEBUG o.s.s.web.util.AntPathRequestMatcher - Request 'GET /loginprocess' doesn't match 'POST /loginprocess
03:29:28.609 [http-bio-8080-exec-11] DEBUG o.s.s.web.util.AntPathRequestMatcher - Request '/loginprocess' matched by universal pattern '/**'

03:29:28.614 [http-bio-8080-exec-20] DEBUG o.s.security.web.FilterChainProxy - /loginprocess at position 4 of 10 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
03:29:28.614 [http-bio-8080-exec-20] DEBUG o.s.s.w.a.UsernamePasswordAuthenticationFilter - Request is to process authentication
03:29:28.615 [http-bio-8080-exec-20] DEBUG o.s.s.w.a.UsernamePasswordAuthenticationFilter - Authentication request failed:    org.springframework.security.authentication.AuthenticationServiceException: Authentication method not supported: GET

我想知道这是否又是同样的问题,因为 Spring Security 向浏览器发送重定向并返回 GET 请求。但是如果登录登陆页面是HTTPS,并且Spring因为RemoteIPValve而认为它是安全的,为什么上面又是一个问题呢?

解决方案

我没有在 RemoteIpValve 中添加 internalProxies 参数,这是导致问题的原因。默认情况下,在 internalProxies 中启用了一些 IP 地址(在我的情况下是这样)。问题是身份验证间歇性地工作。我为 RemoteIpValve 启用了日志,并观察到代理 IP 采用 IpV6 格式,与 internalProxies 不匹配,因此没有为该请求启用 RemoteIpValve,因此出现了问题。#fe80::1%lo0 localhost我在我的 Mac OS X 上注释掉了这条线,问题就消失了。

顺便说一下@M中的配置。Deinum 的回答似乎效果很好。

4

1 回答 1

6

您的 HTTPS 连接由 NGINX 处理。与您的应用程序的连接是 HTTP 连接。所以基本上外面是安全的,里面是不安全的。

Spring Security 使用ServletRequestisSecure()中的方法来确定它是否是安全的,默认情况下这会检查协议是否为 https。

当您使用 tomcat 时,您可以配置一个额外的阀门 RemoteIpValue 3来影响isSecure()getRemoteAddr()方法(和其他一些)的行为。

     <Valve
       className="org.apache.catalina.valves.RemoteIpValve"
       internalProxies="192\.168\.0\.10|192\.168\.0\.11"
       remoteIpHeader="x-forwarded-for"
       proxiesHeader="x-forwarded-by"
       protocolHeader="x-forwarded-proto"
       />

将以上内容添加到<Host >元素中(当然您可能需要删除/修改内部代理参数)。

在您的 Nginx 配置中添加 X-Forwarded-proto 标头。

location / {
    proxy_pass      http://localhost:8080;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Forwarded-Proto $scheme;
    add_header              Front-End-Https   on;
    proxy_set_header Host $http_host;
}

或者只是删除对安全通道的检查并假设一切正常......

链接

  1. ServletRequest.isSecure javadoc
  2. 远程IpValve javadoc
  3. NGinx SSL 代理
于 2013-09-25T08:15:45.657 回答