今天突然想到一个问题关于前后不分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

    忘记是哪个写的了。