今天突然想到一個問題關於前后不分shiro的WEB項目sessionid安全問題.
前后分離可以使用token作為用戶唯一標志憑證,這個token可以自定義生成規則,
那么前后不分的shiro項目返回的是一串32位的字符串,
我們這里假設攻擊方客戶端足夠多,服務端用戶足夠多,
那么在一定時間,攻擊方無限訪問服務端。是否會命中正確的sessionid。
這里,就想着自定義session生成規則。
下面說一下思路。
Springboot整合Shiro的案例以及Shiro架構網上很多。這里就不說了。
1.DefaultWebSecurityManager
/** * 注入 securityManager */ @Bean(name="securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(HashedCredentialsMatcher hashedCredentialsMatcher,SessionManager defaultWebSessionManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 關聯realm. securityManager.setRealm(userRealm(hashedCredentialsMatcher)); securityManager.setSessionManager(defaultWebSessionManager); return securityManager; }
此段代碼是必須的,我們這里需要重新自定義SessionMannager里面的一些實現。因為session是SessionMannager生成的
2.觀察setSessionManager方法
@Override public void setSessionManager(SessionManager sessionManager) { this.sessionMode = null; if (sessionManager != null && !(sessionManager instanceof WebSessionManager)) { if (log.isWarnEnabled()) { String msg = "The " + getClass().getName() + " implementation expects SessionManager instances " + "that implement the " + WebSessionManager.class.getName() + " interface. The " + "configured instance is of type [" + sessionManager.getClass().getName() + "] which does not " + "implement this interface.. This may cause unexpected behavior."; log.warn(msg); } } setInternalSessionManager(sessionManager); }
此處傳入的對象需要是WebSessionManager實例
3.觀察WebSessionManager繼承實現關系,發現DefaultWebSessionManager的父類DefaultSessionManager 有個protected SessionDAO sessionDAO;屬性
4.觀察SessionDAO繼承實現關系抽象類有個SessionIdGenerator接口,這個就是我們需要自己定義的sessionid生成策略了。
5.自定義生成策略
public class SessionIdMine implements SessionIdGenerator{ @Override public Serializable generateId(Session session) { return UUID.randomUUID().toString(); } }
6.將此策略給Spring容器管理
@Bean(name="sessionDAO") public EnterpriseCacheSessionDAO sessionDAO() { EnterpriseCacheSessionDAO abstractSessionDAO=new EnterpriseCacheSessionDAO(); abstractSessionDAO.setSessionIdGenerator(new SessionIdMine()); return abstractSessionDAO; }
EnterpriseCacheSessionDAO為SessionDAO的子類這里需要返回子類作為下一步參數傳遞
7.思考如何將自定義策略實現到shiro,前面說到DefaultWebSessionManager為WebSessionManager最底層實現類,DefaultSessionManager子類,
將DefaultWebSessionManager給Spring管理
@Bean(name="defaultWebSessionManager") public DefaultWebSessionManager defaultWebSessionManager(EnterpriseCacheSessionDAO sessionDAO) { DefaultWebSessionManager abstractSessionDAO=new DefaultWebSessionManager(); abstractSessionDAO.setSessionDAO(sessionDAO); return abstractSessionDAO; }
8.至此自定義策略完成,網上觀察了一些方法,版本不同實現不同,大體思路就是追源碼,看實現
9.效果
10.補充一下Shirodemo測試地址
https://github.com/Rhine404/shirodemo.git
忘記是哪個寫的了。