会话过期后,Apache 代理无法通过 remember-me 令牌正确恢复会话
Apache proxy does not recover session correctly by remember-me token after the session expires
为什么在恢复记住我 cookie 后过期时用户会话无法正常工作?
我在 Spring 安全性中启用记住我选项时出现特殊错误。当会话过期时,我可以浏览其余网页,但注销和其他 POST 方法会在服务器中产生错误。它们不起作用,因为我的控制器收到 GET 方法而不是 POST。我不明白为什么。
首先,我有一个 Apache httpd 服务作为代理,具有 ProxyPass 配置。我将我的 .war 部署为 ROOT.war 因为我想在没有指示的情况下访问我的域 www.example.com应用程序名称(换句话说,我不想指示 www.example.com/appName)
我已经阅读了很多关于这个案例的文档,我在虚拟主机中的配置有以下几行:
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://example.com:9080/
ProxyPassReverse / http://example.com:9080/
<Location />
Order allow,deny
Allow from all
</Location>
#FIX For Spring Security
RewriteEngine on
RewriteRule ^/(.*)$ http://example.com:9080/ [P,L]
在使用表单进行正常身份验证后,post 方法需要 Spring 安全指令的修复。
问题
在 JSSESIONID cookie 过期之前,我可以正确使用该应用程序:我可以注销,我可以使用其他方法 post,等等...这里没有问题。但是 当会话过期时,任何东西都被破坏了。我可以浏览网页、访问信息,而且我永远不会被重定向到登录页面以进行身份验证(我知道 remember-me cockie 有效),但是如果我使用 POST 方法,我会遇到问题: 我的控制器拒绝请求,因为接收到 GET 方法。
我在相同的环境中测试了该应用程序,但在安全性中禁用了记住我的配置-context.xml,部署ROOT.war,并在会话过期时测试该应用程序...和... .我正确地重定向到登录页面。
在本地 tomcat(没有 apache 代理),我的 webapp 在两种配置下都能正常工作:有 remember-me 和没有 remember-me。
安全-context.xml
<bean id="csrfSecurityRequestMatcher" class="com.XXX.YYY.config.CsrfSecurityRequestMatcher"></bean>
<security:form-login
authentication-success-handler-ref="customAuthenticationSuccessHandler"
authentication-failure-url="/login?error"
login-page="/login"
password-parameter="lgPassword"
username-parameter="lgUsername" />
<security:logout
success-handler-ref="customLogoutSuccessHandler"
logout-url="/logout"
invalidate-session="true" />
<security:csrf
request-matcher-ref="csrfSecurityRequestMatcher"
disabled="false" />
<security:remember-me
user-service-ref="customUserDetailsService"
token-repository-ref="customPersistentTokenRepository"
remember-me-parameter="lgRememberMe"
remember-me-cookie="TRMMBRM"
token-validity-seconds="7776000" />
<security:session-management>
<security:concurrency-control
max-sessions="1"
expired-url="/login" />
</security:session-management>
web.xml(我认为配置对于这种情况更重要...)
...
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
...
<filter>
<display-name>springSecurityFilterChain</display-name>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Session Configuration-->
<session-config>
<session-timeout>1</session-timeout> <!-- (in minutes (1 min for test) -->
</session-config>
- JVM 版本:1.8.0_151-b12
- SpringMVC 4.3.5.RELEASE
- Spring 安全 4.2.1.RELEASE
- Apache/2.4.6 (CentOS)
- Apache Tomcat/7.0.76
我也为方法启用了 CSRF 令牌,并过滤了请求,因为避免了处理 paypal 方法。安全配置-spring.xml
CsrfSecurityRequestMatcher.java(我不知道这对这个问题是否重要 -> 如果不需要则忽略)
package com.XXX.YYY.config;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
public class CsrfSecurityRequestMatcher implements RequestMatcher {
private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
// Deshabilitamos la protección CSRF de las siguientes URLs:
private AntPathRequestMatcher[] requestMatchers = { new AntPathRequestMatcher("/paypal/**") };
@Override
public boolean matches(HttpServletRequest request) {
if(allowedMethods.matcher(request.getMethod()).matches()){
return false;
}
// Si la peticion coincide con el patrón a ignorar deshabilitamos la protección CSRF
for (AntPathRequestMatcher rm : requestMatchers) {
if (rm.matches(request)) { return false; }
}
return true;
}
}
我终于解决了这个问题:
- Link 类似问题:Spring Security: invalid-session-url versus logout-success-url
- Spring 安全的官方文档:https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ns-session-mgmt
- 正在看笔记[8]https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ftn.d0e1047
[8] If you are running your application behind a proxy, you may also
be able to remove the session cookie by configuring the proxy server.
<LocationMatch "/tutorial/j_spring_security_logout">
Header always set Set-Cookie "JSESSIONID=;Path=/tutorial;Expires=Thu, 01 Jan 1970 00:00:00 GMT"
</LocationMatch>
为什么在恢复记住我 cookie 后过期时用户会话无法正常工作?
我在 Spring 安全性中启用记住我选项时出现特殊错误。当会话过期时,我可以浏览其余网页,但注销和其他 POST 方法会在服务器中产生错误。它们不起作用,因为我的控制器收到 GET 方法而不是 POST。我不明白为什么。
首先,我有一个 Apache httpd 服务作为代理,具有 ProxyPass 配置。我将我的 .war 部署为 ROOT.war 因为我想在没有指示的情况下访问我的域 www.example.com应用程序名称(换句话说,我不想指示 www.example.com/appName)
我已经阅读了很多关于这个案例的文档,我在虚拟主机中的配置有以下几行:
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://example.com:9080/
ProxyPassReverse / http://example.com:9080/
<Location />
Order allow,deny
Allow from all
</Location>
#FIX For Spring Security
RewriteEngine on
RewriteRule ^/(.*)$ http://example.com:9080/ [P,L]
在使用表单进行正常身份验证后,post 方法需要 Spring 安全指令的修复。
问题
在 JSSESIONID cookie 过期之前,我可以正确使用该应用程序:我可以注销,我可以使用其他方法 post,等等...这里没有问题。但是 当会话过期时,任何东西都被破坏了。我可以浏览网页、访问信息,而且我永远不会被重定向到登录页面以进行身份验证(我知道 remember-me cockie 有效),但是如果我使用 POST 方法,我会遇到问题: 我的控制器拒绝请求,因为接收到 GET 方法。
我在相同的环境中测试了该应用程序,但在安全性中禁用了记住我的配置-context.xml,部署ROOT.war,并在会话过期时测试该应用程序...和... .我正确地重定向到登录页面。
在本地 tomcat(没有 apache 代理),我的 webapp 在两种配置下都能正常工作:有 remember-me 和没有 remember-me。
安全-context.xml
<bean id="csrfSecurityRequestMatcher" class="com.XXX.YYY.config.CsrfSecurityRequestMatcher"></bean>
<security:form-login
authentication-success-handler-ref="customAuthenticationSuccessHandler"
authentication-failure-url="/login?error"
login-page="/login"
password-parameter="lgPassword"
username-parameter="lgUsername" />
<security:logout
success-handler-ref="customLogoutSuccessHandler"
logout-url="/logout"
invalidate-session="true" />
<security:csrf
request-matcher-ref="csrfSecurityRequestMatcher"
disabled="false" />
<security:remember-me
user-service-ref="customUserDetailsService"
token-repository-ref="customPersistentTokenRepository"
remember-me-parameter="lgRememberMe"
remember-me-cookie="TRMMBRM"
token-validity-seconds="7776000" />
<security:session-management>
<security:concurrency-control
max-sessions="1"
expired-url="/login" />
</security:session-management>
web.xml(我认为配置对于这种情况更重要...)
...
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
...
<filter>
<display-name>springSecurityFilterChain</display-name>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Session Configuration-->
<session-config>
<session-timeout>1</session-timeout> <!-- (in minutes (1 min for test) -->
</session-config>
- JVM 版本:1.8.0_151-b12
- SpringMVC 4.3.5.RELEASE
- Spring 安全 4.2.1.RELEASE
- Apache/2.4.6 (CentOS)
- Apache Tomcat/7.0.76
我也为方法启用了 CSRF 令牌,并过滤了请求,因为避免了处理 paypal 方法。安全配置-spring.xml
CsrfSecurityRequestMatcher.java(我不知道这对这个问题是否重要 -> 如果不需要则忽略)
package com.XXX.YYY.config;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
public class CsrfSecurityRequestMatcher implements RequestMatcher {
private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
// Deshabilitamos la protección CSRF de las siguientes URLs:
private AntPathRequestMatcher[] requestMatchers = { new AntPathRequestMatcher("/paypal/**") };
@Override
public boolean matches(HttpServletRequest request) {
if(allowedMethods.matcher(request.getMethod()).matches()){
return false;
}
// Si la peticion coincide con el patrón a ignorar deshabilitamos la protección CSRF
for (AntPathRequestMatcher rm : requestMatchers) {
if (rm.matches(request)) { return false; }
}
return true;
}
}
我终于解决了这个问题:
- Link 类似问题:Spring Security: invalid-session-url versus logout-success-url
- Spring 安全的官方文档:https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ns-session-mgmt
- 正在看笔记[8]https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ftn.d0e1047
[8] If you are running your application behind a proxy, you may also be able to remove the session cookie by configuring the proxy server.
<LocationMatch "/tutorial/j_spring_security_logout"> Header always set Set-Cookie "JSESSIONID=;Path=/tutorial;Expires=Thu, 01 Jan 1970 00:00:00 GMT" </LocationMatch>