深入理解Shiro反序列化原理

前言Shiro是一个功能强大且易于使用的JAVA安全框架,提供全面的身份验证、授权、密码管理和会话管理功能 。它支持多种认证方式,如基于表单、HTTP基本身份验证和RememberMe 。授权模型灵活,可细粒度限制访问控制,保护敏感数据和功能 。安全会话管理功能确保会话安全,包括记住我功能和会话超时设置 。无论是Web应用还是其他Java应用,Shiro都是可靠的选择,增加应用程序的安全性 。
在shiro-core库中实现了对认证授权等的抽象,以提供对不同环境的认证和授权 。如shiro-web依赖就是对在shiro-core库的技术上进行扩展实现web应用的认证和授权等 。在shiro-core库中包括SecurityManager,Authenticator,Authoriser,realm,sessionManager等核心组件,具体关系如下图所示 。

深入理解Shiro反序列化原理

文章插图
image
从整体看是由SecurityManager管理的,然后认证和授权依赖于底层的realm从不同的途径获取对应数据 。整个过程过程中的加密算法是由Cryptography完成的,在shiro中默认支持的加密算法有MD5/Hash/AES/RSA等 。最后由sessionManager进行会话管理,同时还有session缓存等机制支持 。
环境搭建这里可以直接直接把官网的项目拉下来使用 。
git clone https://Github.com/Apache/shiro.gitgit checkout shiro-root-1.2.4 //切换到1.2.4版本打开后需要修改shiro/samples/web/pom.xml路径下jstl的依赖版本,否则会出现jsp解析报错 。
深入理解Shiro反序列化原理

文章插图
image
最后配置好Tomcat,然后选择对应项目就可以跑起来了 。
深入理解Shiro反序列化原理

文章插图
image
深入理解Shiro反序列化原理

文章插图
image
源码分析入口点shiro与web应用是通过一个过滤器绑定的,在web.xml中就可以看到 。
深入理解Shiro反序列化原理

文章插图
image
所有的请求都将被ShiroFilter拦截,同时在过滤器之前还有一个listener,它在filter之前被初始化,它的作用就是为ShiroFilter初始化提供web环境的依赖对象 。
ShiroFilter初始化ShiroFilter是Filter的子类,由于它的匹配规则是/*,所以所有的请求都会被他处理 。先来看一下它的继承关系 。
深入理解Shiro反序列化原理

文章插图
image
首先找到对应的初始化方法org.apache.shiro.web.servlet.AbstractFilter#init 。
public final void init(FilterConfig filterConfig) throws ServletException {setFilterConfig(filterConfig);try {onFilterConfigSet();} catch (Exception e) {......}public void setFilterConfig(FilterConfig filterConfig) {this.filterConfig = filterConfig;setServletContext(filterConfig.getServletContext());//设置servletContext}其中的参数FilterConfig是由调用者ApplicationFilterConfig初始化时传递的自身,每一个filter都由ApplicationFilterConfig来管理最后存放在StandardContext#filterConfigs中 。具体filter初始化的代码就不再深入了,有兴趣的同学可以再去结合tomcat的源码看看,有助于后面学习通过shiro注入filter内存码 。
protected final void onFilterConfigSet() throws Exception {//added in 1.2 for SHIRO-287:applyStaticSecurityManagerEnabledConfig();//安全配置检查是否使用静态安全管理器init();ensureSecurityManager();//检查securitymanager,否则初始化DefaultWebSecurityManager//added in 1.2 for SHIRO-287:if (isStaticSecurityManagerEnabled()) {SecurityUtils.setSecurityManager(getSecurityManager());}}public void init() throws Exception {WebEnvironment env = WebUtils.getRequiredWebEnvironment(getServletContext());setSecurityManager(env.getWebSecurityManager());FilterChAInResolver resolver = env.getFilterChainResolver();if (resolver != null) {setFilterChainResolver(resolver);}}这里才调用了ShiroFilter#init方法,首先从servletContext中获取WebEnvironment对象,这个对象是在前面配置的listener初始化时创建的 。同时初始化了securityManager对象,最后从WebEnvironment中获取SecurityManager以及FilterChainResolver(内置过滤器) 。
WebEnvironment创建在前面的web.xml配置文件中可以看到除了filter之外还配置了一个EnvironmentLoaderListener,在初始化时就会调用其父类的EnvironmentLoader#initEnvironment方法 。
深入理解Shiro反序列化原理

文章插图
image
前面看到在EnvironmentLoaderListener初始化中创建了WebEnvironment对象,调用了createEnvironment方法 。
protected WebEnvironment createEnvironment(ServletContext sc) {Class<?> clazz = determineWebEnvironmentClass(sc);....MutableWebEnvironment environment = (MutableWebEnvironment) ClassUtils.newInstance(clazz);environment.setServletContext(sc);...customizeEnvironment(environment);LifecycleUtils.init(environment);return environment;}protected Class<?> determineWebEnvironmentClass(ServletContext servletContext) {String className = servletContext.getInitParameter(ENVIRONMENT_CLASS_PARAM);if (className != null) {try {return ClassUtils.forName(className);} catch (UnknownClassException ex) {throw new ConfigurationException("Failed to load custom WebEnvironment class [" + className + "]", ex);}} else {return IniWebEnvironment.class;}}


推荐阅读