shiro反序列化漏洞解决方案
总结下来就是shiro的“记住我”的功能用到了AES加密,但是密钥是硬编码在代码里的,所以很容易拿到密钥,因为 AES 是对称加密,即加密密钥也同样是解密密钥,所以就可以通过恶意构建Cookie获取权限执行攻击命令,拿到root权限,官方解决的方案是简单的弃用了问题代码,所以建议是升级shiro版本,避免该问题,新版本到shiro 1.2.5及以上版本,但可能也不行,问题出在哪里呢,升级shiro版本后仍然存在反序列化漏洞,其原因是因为我们使用了别人的开源框架,他们在代码里会配置shiro的密钥,而关键代码可以在github上通过api search接口搜索到,从而得到一个所谓的key包,其实就是这些密钥的集合,然后用这些公开的密钥去轮流尝试,如果你用了开源的框架,而没有修改shiro的密钥,其实这就相当于你使用的shiro密钥已经泄露,这是非常危险的
明白了问题所在,解决就很简单了:
1.确定自己使用的shiro版本要高于1.2.4;
2.在代码中全局搜索 "setCipherKey(Base64.decode(" 关键字,或者"setCipherKey"方法,Base64.decode()中的字符串就是shiro的密钥,要确保该密钥的安全性,千万不要使用公开的密钥。
代码如下:
1.确定自己使用的shiro版本要高于1.2.4;
2.在代码中全局搜索 "setCipherKey(Base64.decode(" 关键字,或者"setCipherKey"方法,Base64.decode()中的字符串就是shiro的密钥,要确保该密钥的安全性,千万不要使用公开的密钥。
/** * 随机生成秘钥,参考org.apache.shiro.crypto.AbstractSymmetricCipherService#generateNewKey(int) * * @return 随机生成秘钥 */ @Bean public static byte[] generateNewKey() { KeyGenerator keyGenerator; try { keyGenerator = KeyGenerator.getInstance("AES"); } catch (NoSuchAlgorithmException e) { String msg = "Unable to acquire AES algorithm. This is required to function."; throw new IllegalStateException(msg, e); } keyGenerator.init(128); SecretKey secretKey = keyGenerator.generateKey(); byte[] encoded = secretKey.getEncoded(); log.info("生成随机秘钥成功!"); return encoded; }
/* * rememberMeManager * @return * 解决shiro反序列号漏洞 * ranqw add */ @Bean(name = " rememberMeManager") public CookieRememberMeManager getRememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); //生成新的密钥 cookieRememberMeManager.setCipherKey(Base64.decode(GenerateCipherKey.generateNewKey())); cookieRememberMeManager.setCookie(getRememberMeCookie()); return cookieRememberMeManager; } /** * cookie对象; * * @return ranqw add */ public SimpleCookie getRememberMeCookie() { //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); simpleCookie.setHttpOnly(true); //cookie生效时间30天,单位秒; simpleCookie.setMaxAge(2592000); return simpleCookie; } @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager() { DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager(); // 设置realm dwsm.setRealm(getShiroRealm()); // 注入缓存管理器 dwsm.setCacheManager(getEhCacheManager()); // 使用记住我 dwsm.setRememberMeManager(getRememberMeManager()); return dwsm; }