apache shiro 反序列化漏洞解决方案

目录

一、反序列化漏洞介绍

二、产生原因

三、解决方案

方案1:升级shiro至最新版本1.7.1

方案2:保持shiro版本不变<=1.2.4,修改rememberMe默认密钥

方案3:禁用rememberMe功能

四、总结


一、反序列化漏洞介绍

序列化:把对象转换为字符串或者字节流的过程。
反序列化:把字符串或者字节流恢复为对象的过程。
反序列化漏洞的产生原理,即黑客通过构造恶意的序列化数据,从而控制应用在反序列化过程中需要调用的类方法,最终实现任意方法调用。如果在这些方法中有命令执行的方法,黑客就可以在服务器上执行任意的命令。

二、产生原因

shiro提供了记住我(RememberMe)的功能,即可以在关闭浏览器的情况下,下次打开时还能记住你是谁,无需登录即可访问。
shiro默认使用了CookieRememberMeManager来管理RememberMe cookie, 其处理cookie的流程是:
1:生成cookie:序列化 => 使用密钥进行AES加密 => Base64编码,最后返回客户端 remebreme Cookie;
2: 识别cookie:得到rememberMe的cookie值=>Base64解码=>使用密钥进行AES解密=>反序列化。
这个通过观察shiro1.2.4版本的源代码可以发现,如果不指定密钥,shiro会默认一个初始化密钥,该密钥是被硬编码在代码中,由于代码是开源的,攻击者很容易找到该密钥,并且伪造cookie发起攻击。

总结:漏洞产生的根本原因是密钥泄露,比如使用网上公开的密钥,也会存在这个问题。

三、解决方案

方案1:升级shiro至最新版本1.7.1

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.7.1</version>
        </dependency>

密钥硬编码问题存在于1.2.4版本及以下。通过观察最新版本1.7.1的源代码发现,如果不指定密钥shiro会初始化一个随机密钥,由于密钥是随机生成的,所以攻击者没办法猜测到密钥。
注意 这是在使用shiro默认密钥的情况下,如果应用修改了默认密钥则需要保证该密钥不是公开的,并妥善保管防止泄露。

测试1.2.4版本升级至1.7.1版本可以互相兼容,无需修改原有代码。

存在的问题:后台重启后,cookie解密失败,导致remembeMe功能失效。

原因:由于重启后,会重新生成一个随机密钥,导致重启前生成的密钥和重启后的密钥发生变化导致cookie解密失败 。

elegate RememberMeManager instance of type [org.apache.shiro.web.mgt.CookieRememberMeManager] threw an exception during getRememberedPrincipals().org.apache.shiro.crypto.CryptoException: Unable to execute 'doFinal' with cipher instance [javax.crypto.Cipher@1ac73e7].

方案2:保持shiro版本不变<=1.2.4,修改rememberMe默认密钥

1.shiro采用xml方式配置(spring+springMVC+xx)

<!-- 定义Shiro安全管理配置 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<!-- 指定Shiro验证用户登录的类为自定义的Realm(若有多个Realm,可用[realms]属性代替) -->
		<property name="realm" ref="systemAuthorizingRealm" />
		<property name="sessionManager" ref="sessionManager" />
		<property name="cacheManager" ref="shiroCacheManager" />
		<!--注入rememberMe cookie管理器-->
    <property name="rememberMeManager" ref="rememberMeManager"/>
	</bean>
 
	<!-- rememberMe管理器 -->
	<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
    <!-- 密钥 调用ShiroCustomAESKeyUtil.getKey()生成 -->
		 <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('WVYw571OG4BehqT7I6J3mA==')}"/>
	</bean>

2.springboot 项目

//将自己的验证方式加入容器
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        return myShiroRealm;
    }

    //权限管理,配置主要是Realm的管理认证
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        // 记住我
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    /**
     * 记住我
     */
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        //密钥 调用ShiroCustomAESKeyUtil.getKey()生成
        String cipherKey= "+h+zZswHRTUerMhr9Dkm2g==";
     cookieRememberMeManager.setCipherKey(org.apache.shiro.codec.Base64
.decode(cipherKey));
        return cookieRememberMeManager;
    }

密钥生成工具

import org.apache.shiro.crypto.AesCipherService;

import java.security.Key;

public class ShiroCustomAESKeyUtil {
    public static String getKey(){
        AesCipherService aesCipherService = new AesCipherService();
        Key key = aesCipherService.generateNewKey();
        return java.util.Base64.getEncoder().encodeToString(key.getEncoded());
    }
}

注意: 应该妥善保存密钥,防止泄露,密钥使用随机生成的,不要copy网上的,否则密钥泄露安全问题依然存在。

方案3:禁用rememberMe功能

由于该漏洞是rememberMe功能引起,禁用rememberMe 也可以起到防护作用,如果项目不需要rememberMe功能倒是可以考虑。

四、总结

综合考虑建议采用升级shiro版本(方案1)+修改密钥(方案2)的方式。该方式解决默认密钥硬编码的问题,同时也防止重启后密钥改变导致重启前的remeberme cookie失效的问题。

  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值