總結下來就是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; }