【问题标题】:Error with cookie-value when adding a new Spring Session添加新的 Spring Session 时 cookie 值出错
【发布时间】:2016-12-05 20:19:39
【问题描述】:

在我的基于Spring Boot 1.4 的应用程序中,我使用Spring Session 将会话数据存储在带有JDBC 的数据库中。

这适用于默认会话。但是当我想添加一个新会话时(通过将 ?_s=1 添加到应用程序 url)我得到以下异常:

java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value

这里有什么问题?

编辑:请注意,我自己并没有设置 cookie 值,Spring Session 会这样做。因此我不知道它试图设置哪个值。

完整的堆栈跟踪在这里:

java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value
    at org.apache.tomcat.util.http.Rfc6265CookieProcessor.validateCookieValue(Rfc6265CookieProcessor.java:160) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.tomcat.util.http.Rfc6265CookieProcessor.generateHeader(Rfc6265CookieProcessor.java:109) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.connector.Response.generateCookieString(Response.java:989) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.connector.Response.addCookie(Response.java:937) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.connector.ResponseFacade.addCookie(ResponseFacade.java:386) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.session.web.http.DefaultCookieSerializer.writeCookieValue(DefaultCookieSerializer.java:112) ~[spring-session-1.2.1.RELEASE.jar:na]
    at org.springframework.session.web.http.CookieHttpSessionStrategy.onNewSession(CookieHttpSessionStrategy.java:213) ~[spring-session-1.2.1.RELEASE.jar:na]
    at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.java:247) ~[spring-session-1.2.1.RELEASE.jar:na]
    at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.access$100(SessionRepositoryFilter.java:214) ~[spring-session-1.2.1.RELEASE.jar:na]
    at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryResponseWrapper.onResponseCommitted(SessionRepositoryFilter.java:202) ~[spring-session-1.2.1.RELEASE.jar:na]
    at org.springframework.session.web.http.OnCommittedResponseWrapper.doOnResponseCommitted(OnCommittedResponseWrapper.java:226) ~[spring-session-1.2.1.RELEASE.jar:na]
    at org.springframework.session.web.http.OnCommittedResponseWrapper.sendRedirect(OnCommittedResponseWrapper.java:126) ~[spring-session-1.2.1.RELEASE.jar:na]
    at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:138) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:138) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.security.web.firewall.FirewalledResponse.sendRedirect(FirewalledResponse.java:41) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:138) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.security.web.util.OnCommittedResponseWrapper.sendRedirect(OnCommittedResponseWrapper.java:128) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:138) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.security.web.util.OnCommittedResponseWrapper.sendRedirect(OnCommittedResponseWrapper.java:128) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.DefaultRedirectStrategy.sendRedirect(DefaultRedirectStrategy.java:57) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint.commence(LoginUrlAuthenticationEntryPoint.java:169) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.access.ExceptionTranslationFilter.sendStartAuthentication(ExceptionTranslationFilter.java:204) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.access.ExceptionTranslationFilter.handleSpringSecurityException(ExceptionTranslationFilter.java:178) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:134) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:150) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:164) ~[spring-session-1.2.1.RELEASE.jar:na]
    at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:80) ~[spring-session-1.2.1.RELEASE.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:108) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:522) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1110) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:785) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1425) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_101]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_101]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_101]

【问题讨论】:

标签: java spring-boot spring-session


【解决方案1】:

这是由于 Tomcat 的 cookie 处理在 8.5 中默认更改为符合 RFC 6265 的实现,其中不允许空格(字符 32)等。

作为一种解决方法,您可以将 Tomcat 配置为使用旧的 cookie 处理器。要使用 Spring Boot 执行此操作,请像这样注册 EmbeddedServletContainerCustomizer @Bean

@Bean
public EmbeddedServletContainerCustomizer customizer() {
    return container -> {
        if (container instanceof TomcatEmbeddedServletContainerFactory) {
            TomcatEmbeddedServletContainerFactory tomcat = (TomcatEmbeddedServletContainerFactory) container;
            tomcat.addContextCustomizers(context -> context.setCookieProcessor(new LegacyCookieProcessor()));
        }
    };
}

另请参阅spring-projects/spring-session#gh-605 以跟踪在 Spring Session 中修复此问题的进度。

更新:

上述解决方案适用于 Spring Boot 1.x。从 Spring Boot 2.0 开始,EmbeddedServletContainerCustomizer 已替换为 WebServerFactoryCustomizer,如 Spring Boot 2.0 migration guide 中所述。

另请注意,从 Spring Session 2.0 开始,会话 cookie 默认为 Base64 编码,可防止发生原始问题。

【讨论】:

  • 如何处理 Cookie 中的“=”(Base 64 编码)?旧版 cookie 解析失败。
  • 您好,Spring 2.* 有哪些选项?它的依赖项上没有EmbeddedServletContainerCustomizer。谢谢。
  • @JorgeCampos EmbeddedServletContainerCustomizer 在 Spring Boot 2.0 中已重命名为 WebServerFactoryCustomizer。请参考Spring Boot 2.0 migration guide
  • 感谢韦德兰。赞赏。干杯,
【解决方案2】:

Function cookie 无法正确编码带有空格的值以及法式符号等。我用 URLEncoder.encode(String arg0, Encoding version) 解决了这个问题,这里我使用了 UTF-8。 这里是我创建的方法!

private static void setCookie( HttpServletResponse response, String nom, String valeur, int maxAge )throws IOException { 
    Cookie cookie = new Cookie( nom, URLEncoder.encode( valeur, "UTF-8" ) );
    cookie.setMaxAge( maxAge );
    response.addCookie( cookie );
}

【讨论】:

【解决方案3】:

CookieProcessor 是一个新的配置元素,在 Tomcat 8.0.15 中引入。 CookieProcessor 元素允许在每个 Web 应用程序中进行不同的 cookie 解析配置,或者在默认的 conf/context.xml 文件中全局配置。

根据Apache Tomcat 8 Configuration Reference Version 8.0.47 的官方文档:

CookieProcessor的标准实现是:org.apache.tomcat.util.http.LegacyCookieProcessor。请注意,预计这将在未来的 Tomcat 8 版本中更改为 org.apache.tomcat.util.http.Rfc6265CookieProcessor。

稍后..

根据Apache Tomcat 8 Configuration Reference Version 8.5.23:的官方文档

CookieProcessor的标准实现是org.apache.tomcat.util.http.Rfc6265CookieProcessor。

要解决此问题:在位置 %CATALINA_HOME% 的 conf/context.xml 中添加此行(在我的情况下为 C:\apache-tomcat-8.5.20\conf\context.xml):

<CookieProcessor className="org.apache.tomcat.util.http.LegacyCookieProcessor" />

添加后是这样的:

<?xml version="1.0" encoding="UTF-8"?>

<Context reloadable="true">
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
    <Transaction factory="bitronix.tm.BitronixUserTransactionObjectFactory"/>
    <CookieProcessor className="org.apache.tomcat.util.http.LegacyCookieProcessor" />    
</Context>

【讨论】:

    【解决方案4】:

    不要在 cookie 的内容中使用空格。它提到空格是无效字符。

    【讨论】:

    • 以正确的方式回答,以便他人理解。
    • 我是 Stack Overflow 的新手,所以我知道我发布的答案但如何添加我不知道的代码。
    【解决方案5】:

    我们可以应用 cookieValue.trim() 或 cookieValue.replace(" ", "") 来删除空格 或“spcbefore

    【讨论】:

      猜你喜欢
      • 2021-03-23
      • 2014-10-12
      • 2019-06-24
      • 1970-01-01
      • 1970-01-01
      • 2017-04-02
      • 1970-01-01
      • 1970-01-01
      • 2016-03-21
      相关资源
      最近更新 更多