新闻详情

新闻详情

首页 / 资讯中心 / 详情

若依系统无授权接口访问排查与封堵实战

发布时间:2026/9/9 20:57:59来源:尧图网络
若依系统无授权接口访问排查与封堵实战
做若依管理系统的时候我最怕听到的一句话就是“有个接口不带Token也能直接返回数据。” 这句话意味着你的项目大概率存在“无授权接口访问”问题——某个本应在登录屏障后面的接口被裸奔挂了出去。若依框架虽然内置了完善的权限体系但实际项目里因为配置不当或代码遗漏这种“裸奔接口”并不少见。本文就围绕若依的权限机制聊聊无授权接口访问是怎么产生的、怎么定位、怎么封堵以及我在项目里踩过的坑。如果你是刚上手若依或者正在做若依项目的安全审计这篇文章应该能帮你省不少时间。1. 先搞清楚若依的权限防线是怎么搭的要搞懂“无授权接口访问”不能上来就改配置。我见过很多同学把 SecurityConfig 里的 permitAll 删了又加加了又删最后还是漏。原因就是没理解若依的权限链路。我先用两段话把这条链路捋清楚。1.1 两个分支两种实现但套路一致若依管理系统有两种主流形态单体版和前后端分离版。单体版基于 Shiro前后端分离版基于 Spring Security JWT。以 RuoYi-Vue 为例登录成功后拿到一个 token后续每个请求在 Header 里带上Authorization: Bearer xxx框架通过 JWT 过滤器解析出用户信息放进 SecurityContext。Shiro 那套则用 Session 和 RememberMe逻辑上差不多。我实际项目里用的是 RuoYi-Vue后面讲到的代码默认以它为例。但你会发现如果你用的是 RuoYi-Vue-Plus 或若依微服务 Plus那些增强版本可能把 JWT 换成了 Sa-Token或者引入网关统一鉴权核心还不离其宗先认证再授权。所以排查思路可以平移。1.2 请求进入 Controller 前的两道关卡第一道关卡SecurityFilterChain。在SecurityConfig里几乎每个若依项目都有这样一段配置http.authorizeRequests() .antMatchers(/login, /captchaImage).permitAll() .anyRequest().authenticated() .and() .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)意思是/login和验证码接口可以匿名访问除此之外的所有请求都必须登录。如果框架配置正确大多数未登录请求会在这里被拦截并返回 401。但这里有个关键点如果后续有人把某个业务路径也加到了permitAll里或者干脆写了一个/xxx/**那这个接口就直接裸奔了。第二道关卡方法级权限注解。请求进入 Controller 后若依通过 Spring Security 的全局方法安全机制拦截带有PreAuthorize注解的方法。例如PreAuthorize(ss.hasPermi(system:user:list)) GetMapping(/list) public TableDataInfo list(SysUser user) { startPage(); ListSysUser list userService.selectUserList(user); return getDataTable(list); }这里ss.hasPermi(...)会去比对当前登录用户的权限集合里有没有system:user:list。没有对应权限就抛出 AccessDeniedException。问题在于若依框架本身并不会强制要求每个接口都写这个注解。代码生成器倒是会帮你生成但如果你手写 Controller或者从网上抄了一段代码很容易漏掉。漏掉注解不等于不能访问——只要第一道关卡通过了它就能被登录用户直接调用。如果第一道关卡也被人为放行了那就是彻底的“无授权访问”。1.3 匿名名单、权限标识与数据权限的关系需要明确permitAll、PreAuthorize、DataScope 是三层不同纬度的控制。匿名名单控制的是“要不要登录”PreAuthorize 控制的是“登录后有没有某按钮权限”DataScope 控制的是“是否有权看某些部门/用户的数据”。三层都要对才安全。在排查无授权接口时优先检查第一层和第二层第三层一般不会被单独当“无授权”报出来但如果数据接口没控制效果类似泄露。提示不要以为接口路径不在 permitAll 里就安全。如果你用了自定义 Filter 或拦截器或者把接口定义在框架包扫描范围之外Spring Security 可能管不到它。这个问题后面会讲。2. 无授权接口访问到底是哪来的2.1 先分清楚是“匿名访问”还是“越权访问”在若依项目里无授权接口访问通常包含两种匿名访问未登录用户直接调用受保护接口拿到数据或执行操作。越权访问登录用户调用了自己角色之外的接口比如普通用户调了管理员接口。很多人在排查时把两者混为一谈。用户反馈“这个接口不需要权限就能访问”可能指的是不带 token 能访问也可能指的是普通账号能访问。排查方向完全不一样。我们先盯住“匿名访问”因为危害最大但如果你把匿名问题修完接口仍然能被低权限账号调用那就是第二种需要补 PreAuthorize。2.2 若依默认允许匿名访问的路径有哪些以官方 RuoYi-Vue 为例SecurityConfig中默认放行的路径大致包括路径用途/login登录接口/captchaImage图形验证码/register注册功能如果开启/*.html, /.css, /.js 等前端静态资源/profile/**本地上传文件访问这些是合理的匿名路径。但很多项目会在此基础上不断追加业务路径。比如把/system/user/list加进permitAll方便测试或者把某个 Cron 回调接口加进去后来忘了删。这是最常见的无授权接口来源。2.3 我在项目里遇到的三种漏网之鱼第一种为了对接第三方开发时临时把对方需要的接口放行比如/api/open/**结果上线前没收紧等于给所有外部请求开了门。第二种用若依的代码生成器生成接口后开发图省事把权限注解删了或者只保留PreAuthorize(ss.hasPermi(xxx))但表达式写错干脆直接不校验。代码生成器的本意是提高效率但很多人只用了它的“生成”没检查它生成的“权限点”。第三种自定义拦截器或 AOP 里做权限校验但拦错了路径、排除了错误包名导致部分请求绕过了框架的过滤器链。这种情况最难查因为从 SecurityConfig 看一切正常。2.4 为什么说“看起来没漏洞”也可能有漏洞Shiro 版和 Spring Security 版在路径匹配规则上有差异。Shiro 的/**是尾匹配Spring Security 的antMatchers(/**)也是通配但如果你同时存在多个匹配规则顺序很重要。Spring Security 默认按anyRequest().authenticated()最后兜底理论上漏网可能性低。但如果项目中加了多个WebSecurityConfigurerAdapter或SecurityFilterChainBean多个配置叠加时可能按加载顺序覆盖掉规则。微服务版更是多了一层网关网关层若放行接口下游即使有认证也拿不到 Token等于直接短路。所以无授权接口访问往往不是“一个 bug”而是“配置 编码习惯”共同造成的。排查时不能只看一处。3. 定位无授权接口一次完整排查实操3.1 先用无痕浏览器验证一遍打开浏览器无痕窗口直接访问一个你认为应该受保护的接口例如http://localhost:8080/system/user/list如果返回了 JSON 数据说明该接口当前处于匿名可访问状态如果跳到登录页或返回 401说明被拦截。这个方法虽然简单但对每个接口手工点一遍太慢适合先抽查几个高风险接口比如用户列表、数据字典、代码生成器接口。像若依里的数据字典管理看起来只是基础数据但一旦被匿名读取往往会把系统的业务枚举信息暴露出去为攻击者提供情报。3.2 从 API 文档拉全接口清单若依项目很多接了 Knife4j 或 Swagger启动项目后访问/doc.html可以看到所有接口。把接口按 Controller 分组整理出来重点看这四类系统管理类/system/**监控类/monitor/**代码生成类/tool/gen/**你新加的业务接口对每一项在无痕模式下访问一次记录返回状态。没有 API 文档的项目可以临时在application.yml里打开 Spring Boot Actuator 的 mappings 端点如果已存在或者用浏览器开发者工具在页面上统计 XHR 请求。3.3 写个小脚本扫出没有权限注解的 Controller这一步是为了在你还没来得及手工验证前先发现潜在风险。我常用一个粗糙的 Python 脚本扫描 Java 源码找出所有RestController或Controller类查看类上和方法上有没有PreAuthorize注解如果类上有注解方法可以继承如果类上和方法上都没有就标记为“疑似无权限控制”。import os import re root rsrc/main/java rest_controller re.compile(r(?:Rest)?Controller) pre_auth re.compile(rPreAuthorize) request_mapping re.compile(r(?:Get|Post|Put|Delete|Request)Mapping) suspicious [] for dirpath, dirnames, filenames in os.walk(root): for name in filenames: if not name.endswith(.java): continue filepath os.path.join(dirpath, name) with open(filepath, r, encodingutf-8) as f: content f.read() if not rest_controller.search(content): continue has_class_preauth bool(pre_auth.search(content.split(class)[0] if class in content else content)) # 按方法块简单切分只做初步筛选 methods re.split(rpublic |protected |private , content) for m in methods: if request_mapping.search(m) and not pre_auth.search(m): suspicious.append((filepath, m[:80].replace(\n, ))) break for item in suspicious: print(检查:, item)这个脚本只是筛查工具会有误报比如接口继承了父类方法、Controller 由权限框架统一拦截、或者用自定义注解做权限控制。但它能帮你快速缩小范围。3.4 手把手验证一个可疑接口假设脚本扫出了/system/user/export没有PreAuthorize。接下来我按这个流程验证看类上是否有权限注解大多数若依 Controller 类上并没有都是方法上有。打开 SecurityConfig确认/system/user/**不在permitAll里。无痕浏览器访问/system/user/export?pageSize10看返回。用普通账号登录后调用该接口看是否能导出所有用户数据。如果第 3 步返回 401说明第一道关卡是拦住匿名访问的但第二道关卡缺失这会导致普通用户越权导出管理员才能导出的数据。如果第 3 步返回 200那说明第一道关卡也被突破了需要重点查 SecurityConfig。3.5 别忘了看日志和网关层在微服务架构下若依微服务 Plus 通常有一个网关模块ruoyi-gateway统一处理 Token 校验。排查时不能只看业务服务的 SecurityConfig。在网关里可能有WhiteListConfig或类似的白名单配置里面会放行登录、验证码等路径。如果业务中有人把/system/**也加进白名单那所有经过网关的系统管理请求都会不携带 Token 直接透传到下游业务服务里就算配了anyRequest().authenticated()也拿不到用户信息最终可能因为异常处理不严谨而返回数据。所以验证接口时要“从网关入口到服务出口”完整走一遍而不是只测某一个端口。4. 封堵无授权访问的几种落地方法4.1 收紧匿名白名单一条一条过第一步永远是把SecurityConfig或ShiroConfig里的匿名路径抠出来逐条审视。Spring Security 版做法.antMatchers( /login, /captchaImage, /register, /profile/**, /*.html, /**/*.css, /**/*.js ).permitAll()凡是不能说明“为什么不需要登录”的一律删掉。特别注意/profile/**是若依放行上传文件的目录如果你不希望匿名用户直接访问静态文件也可以收紧改为登录后访问或再加鉴权。Shiro 版则在ShiroConfig.java的filterChainDefinitionMap.put(...)里修改例如filterChainDefinitionMap.put(/login, anon); filterChainDefinitionMap.put(/captcha.jpg, anon); filterChainDefinitionMap.put(/**, user);如果你用的是shiro的anon一定要确保只放行必要的路径。user表示登录后可访问。别图省事直接put(/**, anon)那等于把门焊死了还上了把锁——但钥匙挂在门口。4.2 给业务接口补权限注解别嫌麻烦如果你希望一个接口只有拥有system:user:list权限的人才可以调用就直接加上注解PreAuthorize(ss.hasPermi(system:user:list)) GetMapping(/list) public TableDataInfo list(SysUser user) { ... }若依的菜单管理里每个菜单/按钮都有一个“权限字符”比如system:user:list。新增接口时在菜单里配好对应权限字符接口就能被权限树控制。不要省这一步。代码生成器生成的接口默认已经带注解但如果你改过模板或手写了自定义 SQL 查询接口一定要单独补上。有个小细节PreAuthorize的表达式里ss是若依自定义的 BeanhasPermi方法可以传多个权限表示“或”关系。如果你写hasPermi(a, b)用户只要有其中一个就行。如果你写的是hasAnyPermi之类需要看框架版本不同版本方法名略有差异。写成错的表达式不会导致“能访问”反而会报 500 权限校验失败所以更容易被发现反而是好事。4.3 用拦截器做一道兜底防线如果项目里历史接口太多一个个补注解工作量太大我建议加一道兜底拦截器。思路是定义一个Anonymous注解只允许在明确标注了该注解的接口上匿名访问默认所有接口必须先通过登录校验。这样即使以后有人忘了加PreAuthorize也不会出现匿名接口。大致代码思路Component public class AuthRequiredInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if (handler instanceof HandlerMethod) { HandlerMethod method (HandlerMethod) handler; // 方法或类上有 Anonymous说明允许匿名 if (method.hasMethodAnnotation(Anonymous.class) || method.getBeanType().isAnnotationPresent(Anonymous.class)) { return true; } // 否则要求必须已登录可结合 Spring Security 或 Sa-Token 判断 if (SecurityUtils.getLoginUser() null) { response.setStatus(HttpStatus.UNAUTHORIZED.value()); return false; } } return true; } }然后注册进 Spring MVC 的拦截器注册表Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authRequiredInterceptor) .addPathPatterns(/**) .excludePathPatterns(/login, /captchaImage, /error); }这样即使 Spring Security 的匿名名单配漏了MVC 拦截器也能拦一道。注意这个拦截器只拦截进入 DispatcherServlet 的请求对于静态资源映射或其他 Filter 路径不一定覆盖。所以它适合作为“兜底”不能完全替代框架配置。4.4 微服务/网关架构下别忽略网关层如果你用的是若依微服务 Plus 这类架构网关层是所有请求的第一道门。推荐的做法是网关负责校验 Token 是否存在、是否过期并将用户信息通过 Header 转发给下游下游各个服务继续用PreAuthorize做细粒度权限校验。网关层维护一个“白名单”只放行/auth/login、/auth/captcha、/code这类真正公开的路径。排查完网关白名单后还有一个容易被忽视的点下游服务之间的内部调用Feign通常不带用户 Token而是通过内部 Header 或 URL 携带用户信息。如果你在内部接口上加了PreAuthorizeFeign 调用很容易因为拿不到用户上下文而失败。很多开发者为了省事会在内部接口上去掉权限注解结果接口也能通过网关直接访问。这属于典型的内外网边界没分清。建议把内部调用接口统一放在/internal/**路径下网关层拒绝外部对该路径的访问下游再做好服务间认证。4.5 数据权限也要顺手查一查刚才说的都是“接口有没有门禁”。但“无授权访问”还有一种形态接口有权限注解但查询的是全表数据没有做数据隔离。若依提供了DataScope注解和DataScopeAspect切面系统管理、部门管理的列表查询默认会带上数据范围过滤。如果你自己写业务接口从SysUser表或自定义表里查数据没有加数据权限那么同角色的人也可能看到其他单位的数据。这种情况虽然不属于“匿名”但对外部扫描器和审计来说风险等级同样不低。排查时可以看 SQL 日志里是否自动拼接了dept_id或user_id过滤条件没有的话就要补上。5. 常见问题与避坑实录5.1 问题速查表现象可能原因解决方式未登录能访问/system/user/listSecurityConfig 的permitAll误放行检查匿名名单删除多余路径未登录能访问业务接口但permitAll看起来没问题存在多个 SecurityFilterChain 或网关白名单被放行全局搜索permitAll和WhiteList逐条排查登录用户能访问没有权限的接口Controller 方法缺少PreAuthorize补上权限注解加了PreAuthorize后接口报 500权限表达式写错或ssBean 未被扫描检查表达式确认ss已注册接口有权限注解但返回了所有数据缺少DataScope数据权限在方法上加DataScope并设置deptAlias加了拦截器后静态资源被拦拦截器排除了静态资源路径或资源在别处排除/assets/**,/static/**,/profile/**等网关放行了登录接口但登录一直失败网关透传了Authorization头和登录接口冲突登录接口在网关白名单时前端不要携带无用 Token5.2 三个容易踩的坑第一别用/**做临时放行。我在一个项目里见过有人为了测试新功能把新增模块的 Controller 路径写成了/**以为只影响自己。结果一个测试环境被外部扫描器直接打到用户列表。改正方法很简单放行精确路径不要用通配符兜底。第二改完配置一定要跑回归。有次我把/login从匿名名单里删了结果登录页直接转圈圈验证码也不显示。原因是若依的验证码接口/captchaImage和登录接口都必须匿名访问少一个都不行。改完 SecurityConfig 后至少把登录、验证码、验证码刷新、注册、静态资源访问这几条链路全部跑一遍。第三把“权限注解缺失”当成小问题。很多新手觉得接口没有PreAuthorize也没什么反正登录后才能调。但在企业系统里普通员工和管理员共用一个系统的话这种接口就是权限提升漏洞。不要因为一时方便就跳过注解代码生成器自带的注解也不要删。5.3 我的安全审计习惯上线前我会把无授权接口检查做进发布流程。脚本不是只跑一次而是每次发版都跑。具体动作用 3.3 节的脚本扫一遍新增 Controller标注可疑接口。用无痕浏览器批量请求所有接口统计 401/403 比例。检查application.yml里是否开了knife4j.productiontrue生产环境一定要关掉接口文档。日志里搜一下No mapping和 401 异常高的路径往往能发现扫描器在探测。另外推荐一个土办法在若依的全局异常处理里对AccessDeniedException和AuthenticationException打一条专属日志。一段时间后翻日志如果某个接口频繁出现“未认证访问”那它大概率就是你要封堵的裸奔接口。注意生产环境千万别开着 Swagger/Knife4j 不关。你若依项目里如果用的是增强版记得配置生产环境禁用文档否则接口列表等于直接送给别人。我在接手的一个若依老项目里曾经一次排查出 7 个无授权接口其中两个能被任意人直接导出合同数据。那次之后我就养成了习惯每新增一个接口先想“这个接口如果被匿名访问会泄露什么”再写实现代码。权限不是最后补的功能而是接口设计的一部分。如果你也在维护若依项目建议今天就把那个“不需要权限”的接口清单拉出来过一遍哪怕只发现一个也值了。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

TanStack Query(React Query)Network Mode 全解析:online / always / offlineFirst 三种联网模式的实现原理与实战配置 2026/9/9 21:40:07

TanStack Query(React Query)Network Mode 全解析:online / always / offlineFirst 三种联网模式的实现原理与实战配置

TanStack Query(React Query)Network Mode 全解析:online / always / offlineFirst 三种联网模式的实现原理与实战配置 【免费下载链接】query 🤖 Powerful asynchronous state management, server-state utilities and data fetc…

阅读更多 →
含可再生能源与储能的微电网多阶段鲁棒调度MATLAB复现 2026/9/9 21:40:07

含可再生能源与储能的微电网多阶段鲁棒调度MATLAB复现

MATLAB|含可再生能源和储能的区域微电网多阶段鲁棒调度模型:完整复现与调参思路大概一年前,我接到一个区域微电网项目,用户的核心诉求是“把可再生能源不确定性考虑进去,运行方案不能一遇到波动就废掉”。最开始我用的是常规的确定…

阅读更多 →
中考英语情态动词全攻略:核心考点、易错点与备考策略 2026/9/9 21:40:07

中考英语情态动词全攻略:核心考点、易错点与备考策略

1. 项目概述:为什么情态动词是中考英语的“必争之地”中考英语语法模块里,能让考生稳稳拿分又容易丢分的知识点并不多,情态动词绝对算一个。单看单选题,每年各地中考试卷中涉及情态动词的题目几乎稳定在2~4道,覆盖单项…

阅读更多 →
curl 手册页生成器 managen 完全指南:从选项文档到 curl.1 的自动化流水线 2026/9/9 21:40:07

curl 手册页生成器 managen 完全指南:从选项文档到 curl.1 的自动化流水线

curl 手册页生成器 managen 完全指南:从选项文档到 curl.1 的自动化流水线 【免费下载链接】curl A command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, …

阅读更多 →
DeepSeek V4.1 Flash内测:速度飙升、性能暴涨,150人扩招开启成人礼? 2026/9/9 21:40:07

DeepSeek V4.1 Flash内测:速度飙升、性能暴涨,150人扩招开启成人礼?

【DeepSeek V4.1 Flash开启内测】没有任何预告,DeepSeek V4.1 Flash的中间版本deepseek-v4.1-flash-expires-on-0910开始内测。DeepSeek官方称,“DeepSeek V4.1 Flash采用了新的模型结构,原生多模态支持、能力更强、速度更快、且成本更低”。…

阅读更多 →
JavaWeb购物商城实战:Servlet+Tomcat+MySQL从开发到部署 2026/9/9 21:37:06

JavaWeb购物商城实战:Servlet+Tomcat+MySQL从开发到部署

简介:这是一份面向JavaWeb初学者的购物商城项目,基于JSPServletMySQL实现,覆盖用户注册登录、商品浏览、购物车管理、订单提交与管理员后台等完整电商流程,适合用来理解MVC分层、DAO模式以及会话与请求处理。压缩包共270个文件&am…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞