shiro.crypto.CryptoException: Unable to correctly extract the Initialization Vector or ciphertext

错误

工程中使用了shiro,最近启动工程后通过接口访问就一直在报错,跟踪了一下源码,发现是cookie导致的。错误如下:

org.apache.shiro.crypto.CryptoException: Unable to correctly extract the Initialization Vector or ciphertext.
at org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:378)
at org.apache.shiro.mgt.AbstractRememberMeManager.decrypt(AbstractRememberMeManager.java:489)
at org.apache.shiro.mgt.AbstractRememberMeManager.convertBytesToPrincipals(AbstractRememberMeManager.java:429)
at org.apache.shiro.mgt.AbstractRememberMeManager.getRememberedPrincipals(AbstractRememberMeManager.java:396)
at org.apache.shiro.mgt.DefaultSecurityManager.getRememberedIdentity(DefaultSecurityManager.java:604)
at org.apache.shiro.mgt.DefaultSecurityManager.resolvePrincipals(DefaultSecurityManager.java:492)
at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:342)
at org.apache.shiro.subject.Subject$Builder.buildSubject(Subject.java:846)
at org.apache.shiro.web.subject.WebSubject$Builder.buildWebSubject(WebSubject.java:148)
at org.apache.shiro.web.servlet.AbstractShiroFilter.createSubject(AbstractShiroFilter.java:292)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:359)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:957)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2476)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2465)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:370)
... 35 more

分析

    /**
     * Default constructor that initializes a {@link DefaultSerializer} as the {@link #getSerializer() serializer} and
     * an {@link AesCipherService} as the {@link #getCipherService() cipherService}.
     */
    public AbstractRememberMeManager() {
        this.serializer = new DefaultSerializer<PrincipalCollection>();
        AesCipherService cipherService = new AesCipherService();
        this.cipherService = cipherService;
        // 默认构造方法调用时,生成新的密钥
        setCipherKey(cipherService.generateNewKey().getEncoded());
    }

   shiro底层有一个AbstractRememberMeManager的抽象实现,它是这个错误的罪魁祸首,服务端在接收cookie时,得到rememberMe的cookie值=>Base64解码=>AES解密=>反序列化(未限制)。
   shiro≤1.2.4版本预设使CookieRememberMeManager,由于AES使用的key泄露,导致反序化的cookie可控,从而引发反序化攻击。而且AbstractRememberMeManager的构造方法中每次都会重新生成对称加密密钥,意味着每次重启工程都会重新生成一对加解密密钥。这就会导致第一次启动工程shiro使用A密钥加密了cookie,第二次启动工程shiro重新生成了密钥B,当用户访问页面时,shiro会用密钥B去解密上一次用密钥A加密的cookie,导致解密失敗,形成报错,所以这不影响使用者登入操作(rememberMe失效罢了),所以这种异常只会在工程重启(shiro清除session)第一次开启页面的时候出现。

解决方案

1.升级shiro版本,shiro>1.2.4之后这个问题有相应的解决措施。
2.配置固定密钥,这种方法不建议,容易泄露。
3.最简单的方式,直接删除浏览器cookie。
以谷歌浏览器为例,直接找到cookie进行删除即可。

shiro.crypto.CryptoException: Unable to correctly extract the Initialization Vector or ciphertext_第1张图片
shiro文档可参考: https://shiro.apache.org/web.html#Web-RememberMeServices

你可能感兴趣的:(java,servlet,java,前端)