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