当前位置: 首页 > news >正文

java代码审计-Shiro认证授权

java代码审计 Shiro认证授权部分

前言:

这两天发现自己读shiro权限这块有点忘了,于是再好好学一遍shiro,然后结合实战代码审计记录练下

1.Shiro 核心组件

shiro中的权限定义:用户,角色,权限 ,如图所示

image-20250927214154522

1、UsernamePasswordToken,Shiro 用来封装用户登录信息,使用用户的登录信息来创建令牌 Token。

2、SecurityManager,Shiro 的核心部分,负责安全认证和授权。

3、Suject,Shiro 的一个抽象概念,包含了用户信息。

4、Realm,开发者自定义的模块,根据项目的需求,验证和授权的逻辑全部写在 Realm 中。

5、AuthenticationInfo,用户的角色信息集合,认证时使用。(来认证看你是什么角色)

6、AuthorzationInfo,用户的权限信息集合,授权时使用(角色拥有什么权限)

7、DefaultWebSecurityManager,安全管理器,开发者自定义的 Realm 需要注入到此进行管理

8、ShiroFilterFactoryBean,过滤器工厂,Shiro的基本运行机制是开发者定制规则,Shiro去执行具体的执行操作

image-20250927215214964

整个过程:首先用户登录,UsernamePasswordToken封装创建token,然后去找Suject查用户信息,接着又SecurityManager负责认证和授权,他会利用到AuthenticationInfo,AuthorzationInfo进行权限和角色的授权

2.Shiro配置

shiro中Realm是用户自己写的模块用来完成,首先来看到ShiroRealm的编写,需要继承抽象类AuthorizingRealm

两个抽象方法必须实现 doGetAuthenticationInfodoGetAuthorizationInfo,这两个方法这样理解,(如果你是admin登录,doGetAuthenticationInfo就是校验你是不是admin,doGetAuthorizationInfo给你的admin账户授权,你的角色和权限)

先来看doGetAuthenticationInfo(用来校验用户正确性,未整合JWT的写法,也就是用账号密码认证)

整个思路是,用户输入的账号密码会封装到AuthenticationToken中,我们取了之后使用用户登录的账号去数据库查询出正确的密码。接着返回SimpleAuthenticationInfo(携带正确的凭证,在这里是密码),其带有了正确的密码会使用默认的CredentialsMatcher()去对比是否正确,然后用户是否正确

image-20250928175022437

image-20250928180521240

ShiroConfig的配置

需要将realm注入到securityManager中

再把securityManager注入ShiroFilterFactoryBean

image-20250928214744065

在ShiroFilterFactoryBean中实现对权限的设置

image-20250928200143917

接着回到实现权限认证的另一个类doGetAuthorizationInfo,这里是通过在数据库中设置对应的perms和roles的值来代表对应的权限和角色。通过Subject拿到用户信息然后设置对应权限角色

image-20250928214117785

3.实际项目

项目地址:https://github.com/jeecgboot/JeecgBoot

shiro整合JWT的写法(也就是用jwttoken认证代替密码认证)

优点:

  1. 实现 “无状态认证”,适配分布式与微服务架构

  2. 减轻服务端存储与性能压力

  3. ...

也是看到doGetAuthenticationInfo。这里和上面不同的是自定义的函数checkUserTokenIsEffect完成了token的校验。SimpleAuthenticationInfo中传入的token自然也是正确的凭证,也就是没有使用shiro自带的校验功能

image-20250928180150468

所以其实这里可以自定义CredentialsMatcher跳过传统的比对逻辑,但是项目中没写也不碍事

public class JwtCredentialsMatcher implements CredentialsMatcher {@Overridepublic boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {// 由于JWT在Realm中已经验证过有效性,这里直接返回true,表示“凭证匹配”return true;}
}

通过实现接口来实现jwt

image-20250928180826184

checkUserTokenIsEffect:如何校验jwt,其实和jwt的原理差不多

主要是这三部,获取用户,然后查询正确的用户信息,然后调用jwtTokenRefresh校验用户是否正确

image-20250928181353211

getLoginUser()查询中会存在一个aes解密,因为数据库进行了aes加密。保证数据安全

image-20250928181556304

ShiroConfig的设置

再把securityManager注入ShiroFilterFactoryBean

image-20250928195005268

配置无需登录即可访问的url

image-20250929120303871

这里添加的过滤器主要是对跨域的支持

image-20250929120538616

在securityManager注入Realm,禁用 Shiro 的会话(Session)存储功能,并配置 Redis 作为缓存管理器,适配无状态认证场景(如 JWT 认证)

@Bean("securityManager")
public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(myRealm);/** 关闭shiro自带的session,详情见文档* http://shiro.apache.org/session-management.html#SessionManagement-* StatelessApplications%28Sessionless%29*/DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();defaultSessionStorageEvaluator.setSessionStorageEnabled(false);subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);securityManager.setSubjectDAO(subjectDAO);//自定义缓存实现,使用redissecurityManager.setCacheManager(redisCacheManager());return securityManager;
}

接着把这整个项目的登录认证授权捋一遍

首先在登录接口输入账号密码后,查询是否存在登录的此用户,如果存在则用户开始密码匹配,每个账户也存在一个加密盐,然后将密码通过PBEWITHMD5andDES算法加密与数据库比对,相同则代表登录成功

image-20250929130610084

登录成功后生成token,这里生成jwt使用的算法是HMAC256,secret为该账户的密码,然后传回前端,即前端就有了这个凭证

image-20250929130825359

登录成功后前端会访问/getUserinfo这个接口带上刚刚返回给前端的token。被jwtfilter拦截。判断当前路径是否有@IngoreAuth路径。然后调用executeLogin()

image-20250929131154643

注解@IgnoreAuth的配置

image-20250929131249362

然后会交给realm登入认证

image-20250929131402102

image-20250929131457285

我们可以重点看看这个自定义的类是如何校验的

checkUserTokenIsEffect:如何校验jwt,其实和jwt的原理差不多

首先也是获取正确的用户,不过如果是从redis中获取的话会经过aes解密,也就是redis中的数据是由aes加密过的,逻辑在handlerObject中

image-20250929131959962

调用jwtTokenRefresh也就是主要的token判断是否合理

image-20250929132155787

这段代码首先从redis中取出token(经过认证后存入的token),发现如果存在token,有效性有问题也刷新。算一个小漏洞,不过危害程度很低,如果攻击者能获取到某用户(如admin用户)的token即使过期,仍然可以利用普通用户的账号密码登录加此admin用户的token伪造高权限。权限维持。因为传入的账号密码是正确的账号密。漏洞利用的条件:某用户token(在redis中)即可

    private static boolean jwtTokenRefresh(String token, String userName, String passWord, RedisUtil redisUtil) {String cacheToken = oConvertUtils.getString(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token));if (oConvertUtils.isNotEmpty(cacheToken)) {// 校验token有效性if (!JwtUtil.verify(cacheToken, userName, passWord)) {String newAuthorization = JwtUtil.sign(userName, passWord);// 设置Toekn缓存有效时间redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, newAuthorization);redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);}return true;}return false;}

当访问需要鉴权的接口时会调用doGetAuthorizationInfo授权,也是从数据库中取对应的角色权限赋值来。

image-20250929150839718

如访问某个接口需要什么权限如下即可

    @PostMapping(value = "/add")@RequiresPermissions("airag:knowledge:add")public Result<String> add(@RequestBody AiragKnowledge airagKnowledge) {airagKnowledge.setStatus(LLMConsts.STATUS_ENABLE);airagKnowledgeService.save(airagKnowledge);return Result.OK("添加成功!");}
http://www.hskmm.com/?act=detail&tid=21103

相关文章:

  • CF868F题解
  • ThinkPHP反序列化分析
  • AT_iroha2019_day4_l 题解
  • AT_abc290_f 题解
  • 一张图读懂绿电直连系统架构 - 智慧园区
  • P5469 [NOI2019] 机器人 题解
  • 题解:P14080 [GESP202509 八级] 最小生成树
  • 实用指南:Spring Cloud Gateway 实战:全局过滤器日志统计与 Prometheus + Grafana 接口耗时监控
  • GTSAM 中自定义因子(Custom Factor)的详解和实战示例 - 指南
  • AtCoder AGC073 A 题解
  • CF506C Mr. Kitayuta vs. Bamboos 51nod1457 小K vs. 竹子 题目分析
  • 北京 意大利 硕士学签/D签 vfs代办 材料清单
  • temp
  • 我有园子了
  • 使用 Jenkins 的流水线方案实施 CI/CD
  • 加密的病例单
  • 详细介绍:视频融合平台EasyCVR构筑智慧交通可视化管理与智能决策中枢
  • docker 在x86上build arm 镜像
  • 9.29软工
  • 不一样的.NET烟火,基于Roslyn的开源代码生成器
  • 复刻江协旋钮控制模块
  • 告别硬编码!5个让Web自动化脚本更稳定的定位策略
  • 从零开始,使用Idea工具搭建一个springboot项目
  • 最优/极值问题的算法选择
  • 第三方控件库的添加和使用
  • C4NR PVP服务器1.2 天穹炮塔更新
  • 树形dp [JOI Open 2020] 发电站 / Power Plant
  • 深入解析:灵画-AI绘画小程序
  • AT_arc156_b [ARC156B] Mex on Blackboard
  • 产品排序