搞Java开发的兄弟应该都有感觉:Spring Boot 上手快、生态全、省事到不行,但越是这种“开箱即用”,越容易在安全上翻车。我这两年帮人复盘过不少项目,发现所谓的“Spring Boot 常见漏洞”,真正栽进去的往往不是某条看不清代码的底层 CVE,而是大家在日常开发里觉得“没问题”的默认配置、顺手写法、想当然的接口逻辑。
今天这篇不打算列一堆 CVE 编号吓人,而是从一线踩坑视角出发,把 Spring Boot 项目里最常见的安全漏洞、攻击路径,以及我自己实操下来真正有用的安全加固方案拆开讲清楚。内容覆盖:SQL 注入、XSS、CSRF、越权、文件上传、SSRF、反序列化、敏感信息泄露这些高频 Bug,再到依赖扫描、Spring Security、JWT、CORS、限流、日志脱敏、配置加密等最佳实践。不论你是刚把第一个 Spring Boot 服务部署上线的新手,还是在带团队做微服务改造的技术负责人,这篇文章都值得你对照自己的项目逐条体检。
1. 先把丑话说在前面:Spring Boot 项目应该怕什么
1.1 默认配置最大的坑不是“性能”,是“暴露面”
Spring Boot 的自动配置省掉了大量手工装配,但也隐藏了许多安全细节。很多项目启动起来压根没意识到,框架自动暴露了多少不该暴露的东西。
最典型的就是几个端点。Spring Boot Actuator 如果被引入了依赖,并且没有单独做权限控制,/actuator/env、/actuator/heapdump、/actuator/beans、/actuator/mappings这些路径默认可能直接裸奔。我见过一个内部系统,把 heapdump 直接挂在公网入口后面,攻击者下载堆转储文件,几分钟就能把数据库用户名、密码、Redis 连接串、各种加密密钥全部翻出来。网上一堆扫描器把 Spring Boot 的 Actuator 路径列进了必测字典,命中率极高,原因就是开发环境养成的习惯直接带到了生产。
我个人的底线是:生产环境无脑关闭 Actuator 所有端点,只保留必要的
health,而且要用独立管理端口承载。治理这种暴露面不是靠运维写几条防火墙规则就完事的,应用自身必须承担责任。
另一个容易被忽视的是默认错误页。Spring Boot 默认返回的 Whitelabel Error Page,在某些版本下会把异常类型、堆栈信息、甚至部分请求参数透出去。虽然新版默认做了脱敏,但如果你自定义了全局异常处理器,却没有注意信息泄露,仍然可能往外吐 SQL 片段或者内部类名。攻击者做信息收集时,这些看起来不起眼的细节比什么都值钱。
1.2 框架漏洞与业务漏洞:哪个才是真威胁
很多人听到“Spring Boot 漏洞”,第一反应是去查框架本身的 CVE。框架漏洞确实需要关注,比如某些 Spring 版本里的 SpEL 注入问题、Spring Cloud Gateway 曾经的 SpEL 表达式 RCE、Log4j2 的 JNDI 注入等,这些一旦爆出来通常都是高危甚至致命。但也正因为 CVE 消息传播快、修复方案明确,大部分团队反而能及时打补丁升级。真正可怕的是业务代码里的逻辑漏洞,这类漏洞没有 CVE,不在扫描器字典里,却占了实际攻击成功案例的大头。
业务逻辑漏洞的典型代表是越权。很多 Spring Boot 项目的接口权限只做了“是否登录”的拦截,没有做“是否本人”的判断,ID 可预测就直接导致水平越权。比如订单详情接口/order/{id},如果没有校验当前登录用户是否属于该订单,攻击者把 ID 一改,别人订单的数据、手机号、地址全部暴露。还有一种垂直越权,接口没有做角色校验,普通用户直接调用管理员接口。这类问题最坑的地方在于代码评审和自动化测试很难发现,因为你平时测试的都是“正常数据”。
所以我的态度是:依赖扫描和框架升级是底线,业务漏洞才是重灾区。安全加固不能只交给渗透测试或者扫描器,必须把安全编码规范渗透进日常开发流程。
2. 高频漏洞怎么攻进来的:从攻击者视角看 Spring Boot 项目
2.1 注入类漏洞:SQL 注入、命令注入、SpEL 注入
SQL 注入在 MyBatis、MyBatis-Plus、JPA 混合使用的项目里仍然大量存在。最典型的是${}和#{}用混。MyBatis 里${}是字符串拼接,#{}是预编译占位符,前者只要被用户输入触达,基本就是白给。比如实现动态排序时,很多人图省事直接order by ${sortField},前端传个sortField=id desc; select ...,一旦拼接进 SQL,轻则泄露数据,重则 getshell。这已经不是一个理论风险,而是攻防演练中打了就中的普遍问题。
- 排序、分组字段的排序名,建议在代码里做白名单映射,而不是直接拼接前端传的参数名。
- 动态表名、动态 SQL 片段场景下,如果确实无法避免
${},必须单独做严格的格式校验,并限制输入字符集。 - 多租户项目里,租户 ID 的拼接是重灾区,规则是:租户 ID 永远从认证上下文获取,绝不从请求参数读取。
命令注入在 Java 里主要出现在Runtime.exec()和ProcessBuilder的使用过程中。开发者的本意往往是调用系统命令处理文件、调用 Python 脚本、执行 ffmpeg,但把用户输入直接拼进命令字符串,结果被注入&&、|、;这类分隔符。防御的思路不是过滤百分号、小括号、空格,而是彻底不用 shell 解释器,改用参数列表形式调用外部命令,避免命令被 shell 二次解释。
SpEL 注入很多人不熟,但它离 Spring 项目特别近。@Value注解里如果用了#{...}表达式,而表达式的值被外部配置可控,或者代码里手动调用了SpelExpressionParser.parseExpression()解析了用户输入,就有可能导致任意代码执行。我自己见过一个规则引擎项目,管理员可以在前端配置表达式规则,后端拿到表达式后没做沙箱直接解析,虽然只是内网工具,但内网穿透之后就是横向移动的跳板。对 SpEL 的防御没有太多花活,核心原则就是:解析表达式时不要加载运行时环境类,不要直接反射到Runtime,能不用表达式引擎就不用了,实在要用请上专门的规则引擎。
2.2 前端类攻击:XSS、CSRF 与 CORS 配置错误
XSS 在 Spring Boot 项目里通常不是后端框架的锅,而是后端返回数据之后前端渲染的方式问题。但如果后端把用户输入的富文本原样存库再原样返回,又缺少输出编码,等于一手好助攻。用 Thymeleaf 做模板渲染时,th:text默认会做 HTML 转义,但th:utext不会,一旦用了后者渲染用户提交的内容,XSS 直接成立。
防御 XSS 的正确姿势,我认为三层:
- 输入侧,对用户提交内容按场景校验长度、格式、字符集,但不做一刀切的转义,因为富文本场景需要保留 HTML。
- 存储侧,尽量将富文本内容转换成安全的 HTML 白名单结构,比如只允许
p、a、img等少数标签,去掉script、iframe、事件属性。推荐用现成工具库做清洗,别自己写正则,写正则很容易绕过。 - 输出侧,默认进行 HTML 编码,明确不使用
th:utext渲染用户内容。
CSRF 在纯后端接口、前后端分离项目里,其实威胁模型已经变化了。以前是 Cookie 自动携带,所以跨站请求伪造很好使;现在很多项目用 Token 放在 Header 里,CSRF 自然失效。但如果你仍然在使用 Cookie 认证方式,且后端接口同时接受application/x-www-form-urlencoded等简单请求类型,CSRF 风险就要重新重视。Spring Security 默认开启 CSRF 防护,前后端分离项目一般会关闭它,关闭的代价就是必须依赖更安全的认证凭证管理。仅供参考的基线是:Token 认证 + 同源校验 + 关键操作二次验证,三者至少占两样。
CORS 配置错误又是一个经典问题。很多人直接写allowedOrigins("*"),然后allowCredentials(true),这俩组合起来等于允许任意网站携带你的 Cookie 跨域请求。如果哪天用户登录态被钓鱼页面利用,后果自行体会。规范做法是维护一个明确的允许源列表,不要把生产域名和调试域名混在一个环境里,且allowCredentials(true)时绝对不能用通配符源。
2.3 文件上传与任意文件读写漏洞
文件上传在 Spring Boot 项目里基本无法避免,头像、附件、导入模板都属于它。最常见的漏洞是在multipart/form-data接口里只校验了 Content-Type,没校验文件真实内容。攻击者把.jsp或.war内容伪装成图片上传,如果后续通过静态资源映射或路径穿越能够访问到该文件,就可能拿到 WebShell。
- 文件名的处理不能信前端,要由服务端重新生成随机文件名,保留原扩展名映射,禁止暴露物理路径。
- 校验文件头部魔数,图片的话看
FF D8 FF这类字节头,而不是看请求头里的 Content-Type。 - 文件存储目录与 Web 应用部署目录分离,存储目录禁止执行脚本。
- 对于图片之类可以二次处理的场景,用工具库重新转码压缩,这样能直接消灭藏在图片里的畸形代码。
- 文件下载接口必须对
path参数做严格校验,禁止用户控制绝对路径或../穿越。我见过一个下载接口直接拼接文件名参数去读服务器本地文件,结果把/etc/passwd下载下来了。
2.4 SSRF、XXE 与反序列化漏洞的实战防御姿势
SSRF 在 Spring Boot 项目里多出现在这几个场景:URL 预览、Webhook 回调、代理跳转、第三方接口转发。攻击者传入一个内网地址或云元数据地址,应用后端去请求该地址,导致内网探测甚至云主机凭证泄漏。
防御 SSRF 的核心是:后端请求地址必须基于服务端配置,不能直接采用用户传入的完整 URL;如果真的需要用户输入域名,也要做 URL 解析和过滤,禁止 IP、内网保留段和云元数据地址。从架构层面,更彻底的办法是让所有后端外部调用走固定网关,由网关统一管控出口白名单。这样应用层自己也断了对外随意发起请求的能力,整体攻击面大大降低。
XXE 在 Java 里主要集中在 DocumentBuilderFactory、SAXParserFactory、XMLDecoder 处理不可信 XML 的场景。很多老项目还在用 XML 做接口报文,而工厂类默认配置对外部实体的解析常常没有关闭。导致读本地文件、内网端口探测都很容易实现。防御手段很直接:显式关闭disallow-doctype-decl、external-general-entities、external-parameter-entities这几个特性,或者干脆切换成 JSON 报文。Java 高版本对 XXE 的默认策略收紧了一些,但依赖具体实现类,不能想当然。
反序列化漏洞是 Java 安全里老生常谈但杀伤力最大的类型。Spring Boot 项目里有几个点容易中招:Redis 的序列化缓存配置、基于 Java 原生序列化的 RPC 传输、消息队列的消息体反序列化。只要反序列化的类路径可控,攻击者通过构造恶意序列化字节流,能直接实现 RCE。
防御上我的建议:
- 不使用 Java 原生序列化,优先用 JSON 方式封装数据。
- 如果必须用原生序列化,在 ObjectInputStream 层做类白名单过滤,只允许项目自定义的基础类型,拒绝其他任何类。这条能挡住绝大多数 gadget 链攻击。
- 及时升级依赖,重点盯常用的库,很多反序列化 gadget 都是知名第三方组件里的。
3. 安全最佳实践:从依赖到代码,逐层把保险丝接上
3.1 依赖与镜像漏洞:扫描动作要能挡在合代码之前
安全的第一道防线是“这不安全的东西别进来”。Spring Boot 项目不管用 Maven 还是 Gradle,都要在构建流程里引入依赖漏洞扫描。个人推荐直接用 OWASP Dependency-Check 的 Maven 插件,配置好了以后能集成进 CI,构建时把 CVE 数据库里的匹配项拉出来,高危漏洞直接卡发布流程。
小项目可以手动执行扫描,大项目就定期跑一次,把报告导出成 HTML 给团队过一遍。核心指标不是“漏洞数变成 0”,而是已知漏洞必须有关联的缓解措施,要么升级版本,要么确认利用条件在当前架构里不成立,且要留下说明记录。
另一个常常被忽略的是基础镜像。如果业务依赖 Tomcat 等组件打了补丁,但基础镜像还是几个月前甚至半年前的版本,那么大量已知漏洞会原封不动带入生产。镜像扫描工具很多,选一个接入镜像仓库即可。镜像原则就一条:能不用 root 运行就不用 root,能减少层就减少层,所有无文件系统写入需求的路径挂只读目录。镜像里不该有的东西一样都不要留,包括编译工具、调试器、包管理缓存。
依赖锁文件的统一管理也很重要。Maven 项目里尽量用父 BOM 统一管理版本号,避免每个模块各写各的版本,导致有些模块打了补丁、有些没打。通过强制约束,确保所有环境拉取到的依赖版本一致,避免出现“本地安全,线上漏洞”的割裂状态。
3.2 配置管理:敏感信息不能活在明文环境变量里
Spring Boot 项目最常见的信息泄露,就是配置裸奔。application.yml里面数据库口令、Redis 口令、短信平台密钥、JWT 签名密钥直接明文写死,然后整个项目代码还推到企业内部 Git 服务器。一旦仓库权限配置失误或者员工账号被盗,等于把系统钥匙直接递出门外。
- 配置里不允许出现真实口令和密钥,统一改成占位符引用。
- 使用配置中心管理敏感配置项,并打开加密存储能力,至少要对配置值做 AES 或 KMS 加密后再落库。
- 本地方便调试用的密钥必须跟生产密钥区分开,加
dev、prod环境标识,且本地调试配置不要进版本库。 - JVM 环境变量和命令行参数带口令的方法虽然常见,但进程列表和日志都可能泄露;建议优先使用密钥管理服务注入环境变量。
- 每次部署后,要检查运行环境变量和启动命令中是否有明文敏感信息,这个可以在发布流程里做成一个检查点,防止哪天偷偷加回去。
这种问题看着不太能挂上“漏洞”的称号,但实际上比很多代码漏洞危害更大,因为敏感信息一旦泄露,攻击成本极低。
3.3 Spring Security 实战配置:从粗粒度到细粒度权限模型
Spring Security 是 Spring Boot 项目做认证授权时最完整的防线,但很多人对它又爱又恨,复杂情况下配置起来确实痛苦。我的建议是别急着上太复杂的模型,先把几个基本盘打扎实:
- 定义明确的白名单路径:登录接口、注册接口、静态资源、健康检查等路径放行,其他一律要认证。
- 会话用 JWT 还是 Spring Session 要想清楚。微服务场景、前后端分离场景我推荐 JWT,但 JWT 要真正用得安全,而不是只图无状态。
- 不要把所有权限逻辑都堆在注解上,也不要把所有逻辑都写在 Filter 里。合理分工是:框架过滤链负责“认证”,业务方法注解负责“授权”,两者结合。
Spring Security 授权可以用@PreAuthorize这类注解,可以在方法级别控制角色和权限表达式。很多项目的坑是注解写得太粗,比如直接写hasRole('ADMIN'),导致很多接口普通员工和经理都能访问;而真正需要数据级隔离的地方(比如本部门数据、本人数据),注解又搞不定,必须在 Service 层里手动校验。所以建议项目里建立两层权限体系:
- 功能级权限用注解,控制“能不能访问这个接口”。
- 数据级权限在服务层统一实现,确保“只能访问自己的数据”。
这两层体系必须在设计方案时想好,不然后期塞权限补丁非常痛苦。
3.4 认证授权细节:JWT、会话管理与双因素机制的取舍
JWT 绝对是我见过争议最大的主题。它本身问题不多,但使用姿势动不动就踩坑。签名的密钥必须足够随机且独立管理,不能写死在代码里;HS256之类的对称签名方式在多个服务共用一套密钥时风险很大,一旦某个服务被攻破,整个系统的信任全部崩溃。更推荐的方式是每个服务独立管理自己的密钥,或者用公钥加密、私钥签名的非对称算法做验证,配合密钥轮换机制。
JWT 的过期时间也是一个容易出问题的地方。过期时间设很长,比如 7 天、30 天,会让业务的泄密窗口变大。稳妥方案是 access token 短过期,比如 30 分钟到 2 小时,同时配合 refresh token 刷新机制。刷新接口本身也要做风险控制,比如检测到更换设备或异常网络环境时,强制要求重新登录。
会话管理还有一个容易被忽视的坑:注销后旧的 token 还能用一段时间。Redis 可以维护一个黑名单,每次校验时确认是否在黑名单内。虽然会带来一次 Redis 查询的性能损耗,但对中大型系统来说值得。另一个细节是登录接口不要搞成无限尝试,要有验证码、图形码或者类似机制,并配合登录失败次数锁定与告警。双因素认证不要全量铺开,可以先从管理员账号、敏感操作接口对齐,普通用户低风险操作暂不强求。优先把高危账号保护住,这比全面铺开更务实。
3.5 网络传输与链路防护:HTTPS、CORS 和限流熔断
Spring Boot 项目本身不强制处理 HTTPS,但对外服务必须要求全链路 HTTPS,否则你传的用户口令、业务数据等于在公网裸奔。很多公司只在 Nginx 层做了 HTTPS 终结,应用内部走 HTTP,这没问题,关键是服务之间非公网链路也要做双向认证或私有网络隔离,避免内网横向窃听。
CORS 在 Spring Boot 里配置特别简单,所以大家反而容易放松。真正应该做的是把允许的来源、方法和 Headers 清单明确写出来,并用配置中心管理,方便上线前按环境调整。凡是可以不用跨域的接口,就不要开跨域配置,减少暴露。
限流和熔断也是安全实践的一部分,尤其是登录接口、短信接口、验证码接口、批量导出接口。我在项目里比较常用的是 Google Guava RateLimiter 或 Alibaba Sentinel,按接口维度配置 QPS 阈值。比如登录接口设置每 IP 每分钟 10 次,短信接口按用户维度每天 5 次。这些配置要能在运行期动态调整,不然一旦线上流量波动,限流参数反而成为误伤用户的原因。从攻击面看,限流不解决漏洞本身,但能大幅拖慢暴力破解和数据爬取的速度,为应急响应争取时间。
3.6 日志与监控:你不能只记日志,还要让日志变得不可用
安全日志是事后追溯的关键,但绝大多数项目的日志都没有好好规划。我之前排查一次数据泄露事件,发现日志里压根没有“谁在什么时候访问了哪个订单”的记录,检查到最后只能通过数据库慢查询日志去猜,非常被动。
日志要素建议做到:用户 ID、操作类型、请求路径、关键参数、响应状态、耗时、来源 IP。敏感字段比如手机号、身份证号、银行卡号、口令、Token 在进入日志前必须脱敏。可以用 Logback 的 PatternLayout 做屏蔽,或者通过拦截器统一对输出字段做脱敏,但要注意不能只对前端返回脱敏、日志层全量裸存,这样日志就变成第二个数据泄露口。
监控告警也不能忽略。项目中至少要配置异常指标和认证失败指标,认证失败次数短时间激增往往是暴力破解的前兆。日志审计系统里如果捕获到大量 401 或 403 错误,立刻触发告警。不要迷信某一个安全产品能挡住所有攻击,日志与监控是安全体系里最接近“真实战场”的部分。
4. 实操复现:给一个 Spring Boot 项目做安全体检的完整流程
4.1 体检环境准备:工具与脚本清单
我会用一套相对固定的流程给项目做安全体检,不一定每个项目全做,但核心步骤都会覆盖。流程大致包括:信息收集、依赖扫描、接口梳理、静态分析、动态测试、配置审查、日志审计。
工具方面没有特别复杂的,简单好用为主:
- OWASP Dependency-Check:Maven 插件版,扫依赖漏洞。
- SpotBugs 或阿里 P3C:静态代码扫描,能发现空指针、未关闭资源以外,也能发现一部分安全编码问题。
- Burp Suite Community:做接口层手工测试,重点是越权和参数篡改。
- Postman / Apifox:梳理接口清单用。
- 各家云平台的安全中心:扫描容器镜像、Web 漏洞和基线检查,可以用作辅助。
- 一些开源 Web 扫描器:比如 Xray、Arachni,在授权范围内进行漏洞扫描。
体检开始前,要确保你已经拿到授权。未经授权的漏洞测试风险很大,这条红线必须守住。
4.2 分步体检操作:从信息收集到越权验证
第一步先跑依赖检查。执行完 OWASP Dependency-Check 后,报告会列出 CVE 编号、CVSS 分数和受影响的版本。把高危项过一遍,判断是否真实可利用,能升级的直接升级;不能立即升级的切走受攻击的依赖链。
第二步梳理接口清单。把所有 Controller 里的@RequestMapping、@GetMapping等导出来,人工对照看哪些接口没有权限控制,哪些接口返回的结果集可能过大。项目过多时,可以把接口清单按模块分给不同开发同学互相审,避免自己看自己代码容易带侥幸心理。
第三步做认证测试。用普通账号调用所有管理端接口,验证每个接口是否都有角色校验,重点检查 POST、PUT、DELETE 这些带副作用的接口。
第四步做越权验证。找一个列表型接口,比如“我的订单列表”,手动将请求里的用户标识或对象 ID 替换成其他用户的值,观察返回数据是否发生变化。这一步通常能挖出一堆水平越权漏洞。
第五步做注入测试。在参数里输入特殊字符,观察接口是否报 SQL 错误、是否返回堆栈异常。报错信息本身就是有效情报,不建议直接在生产系统做大量注入测试,核心接口单独搭环境来验证更可控。
第六步做文件上传测试。只带一个 PDF 后缀的样本上传,再抓包改成 JSP 内容,看能否被访问;再试文件名包含../的情况,看存储目录是否发生跳转。
第七步做信息泄露检查。查看错误响应、源码注释、前端打包文件里的接口地址和密钥占位符,以及项目文档里是否多次出现内部 IP、管理后台地址。
体检完要产出一份问题清单,按严重程度排序,高危要求在 3 天内修复,中危 1 周内,低危一个迭代内处理。
4.3 体检后如何把漏洞修得既安全又不影响业务
修复漏洞最大的阻力不是不会修,而是怕改坏业务。我的习惯是:能用配置解决的就不改代码,能用框架能力解决的就不自己造轮子,能通过网关层面解决的问题不扩散到所有微服务。
比如 SQL 注入里最常见的排序字段问题,我在项目里统一做了一层白名单转换:
private static final Map<String, String> SORT_FIELD_MAPPING = Map.of( "createTime", "created_at", "updateTime", "updated_at", "status", "status" ); public String resolveSortField(String inputField) { String field = SORT_FIELD_MAPPING.getOrDefault(inputField, "created_at"); return field; }前端传过来的排序字段直接查 Map,查不到就回退默认字段,这样从根本上去掉了拼接用户输入的入口。像这类修复,影响范围小、改动量也不大。
权限修复上,我会坚持“宁可先紧后松”。某个接口不确定是否是管理端功能时,先加上管理员权限保护,确认业务侧确实要开放再调整。这样可能会给后续运营带来一点不便,但远比把接口裸奔在公网上更稳。
日志脱敏可以做一个全局的 Jackson 序列化脱敏注解,在实体字段上标上@SensitiveField,让序列化和日志打印同时走脱敏规则。这样做的好处是代码侵入小,后续新增字段只要记得标注解就能自动覆盖。
配置加密如果暂时没有配置中心,就用 Jasypt 对配置里的口令先做加密,启动时通过环境变量传入解密密钥。需要注意的是,解密密钥本身也要妥善保存,不能跟配置文件放一起。
5. 常见问题与排查实录
5.1 安全修复后接口突然无法访问怎么办
最典型的场景是加了 Spring Security 之后,原来可以访问的接口突然全部 401。排查思路:先看过滤链顺序,Spring Security 的过滤器执行顺序搞错会导致认证不生效或直接拦截所有请求;再确认是否所有需要放行的路径都已经配置正确,尤其是静态资源和健康检查;最后看到底是 Spring Security 的匿名访问配置没有匹配到请求的路径格式,比如路径尾斜杠的差异。
遇到这种兼容问题,不要反复改配置,先做一个最小可复现场景,把 Spring Security 过滤链打印出来,理清请求经过的每一步,再决定是调整白名单还是修改请求路径。
5.2 JWT 过期后前端体验与安全拉锯
JWT 过期时间太短,用户频繁掉线,业务反馈很差;过期时间太长,安全风险又大。常见方案是做成双 token:短 token 用于业务接口,长 refresh token 用于刷新。刷新接口要加设备信息校验,refresh token 要支持吊销。这样既照顾体验,又不会让单个 token 的泄漏窗口太长。
5.3 加了脱敏之后日志查询不好用了
脱敏做得太狠确实会影响排查问题的效率。比如手机号全部变成138****1234,客服反馈“用户说就是这个手机号,你告诉我不完整?”我的建议是脱敏按角色分级别:业务日志面向普通运维操作员,需要完整信息时才走专门的审计日志查询权限,并记录查询行为本身。也就是说,敏感数据不是不能看到,而是看的时候要有留痕与权限控制。
5.4 漏洞扫描报告里一堆“高危”但团队人手不足
如果团队人力有限,不必试图一个迭代消灭所有高危漏洞。建议先按资产暴露面和可利用性排优先级,优先修复暴露在公网、无需认证即可触达、且可利用链条短的漏洞。漏洞报告要落到具体负责人和修复时间,每周跟踪一次。不要只管“清零”,否则团队疲于奔命,真正高危的反而修得不仔细。
5.5 后端接口做安全加固后,性能下降明显怎么办
权限校验、加解密、日志脱敏这些操作都会占用资源。如果发现性能下降明显,可以先做几件事:给安全组件加缓存,比如 JWT 的公钥可以缓存一段时间;对用户权限做缓存而非每次查询数据库;加解密逻辑能放网关就放网关,应用层只处理业务;确保安全过滤器链里没有重复执行同类校验。安全不可牺牲业务体验,但也不能以大炮打蚊子,合理缓存与链路裁剪是两手都要抓的。
6. 最后的几条个人体会
我做安全加固踩过不少坑,也总结出一些可能和教科书不完全一致、但更贴近实战的看法。
- 依赖扫描和框架升级要做,但别把所有希望压在这上面。很多 CVE 利用条件在实际场景里根本不成立,但业务逻辑漏洞通常一打一个准。
- 权限设计从第一天就要考虑,不要等快上线再补。数据级权限没法靠网关和过滤器统一解决,它需要服务层对业务数据归属做校验,越晚介入越痛苦。
- 日志脱敏和审计留痕是安全事件追查的救命稻草,不管多小的系统,这两个动作都要做。
- 安全配置要环境区分。开发环境和生产环境的配置不能共享,多环境隔离是基础,连这个都没做好,其他安全建设都是空中楼阁。
- 安全是持续迭代的过程, 不是你上线前做一次加固就完事。每次新功能、新技术栈引入,安全考虑都要跟着一起走一遍,否则一定会埋下新的隐患。
希望这篇内容能给正在做或准备做 Spring Boot 项目的你一些具体参考。如果你手里刚好有项目,可以从依赖扫描和权限梳理开始,先花半天时间做第一轮体检,你会发现自己其实已经足够了解这个系统的风险部分,只是平时没有坐下来认真看它。