今天突然想到一个问题关于前后不分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
忘记是哪个写的了。