SpringBoot 让接口开发变得飞快,但“快”往往意味着安全被抛在脑后。很多项目上线后,接口裸奔,被扫到就是一顿薅。以下5个漏洞,每一个都足以让你半夜被叫起来修数据。
1. 接口裸奔:未授权访问与越权
最常见的漏洞:接口只做了登录校验,没做权限校验。比如/api/user/{id}只判断了“有没有登录”,却没判断“这个 id 是不是当前用户的”。结果 A 用户改一下 URL 里的 id,就能看到 B 用户的订单、地址甚至身份证号。垂直越权更可怕:普通用户直接访问/api/admin/deleteUser,如果后端只靠前端隐藏菜单,那等于没防。
堵法:引入 Spring Security 或 Shiro,给每个接口明确权限注解,如@PreAuthorize("hasRole('ADMIN')")。对于资源归属,必须在 Service 层校验currentUserId.equals(resource.getUserId()),别信前端传的任何用户标识。记住:前端校验是体验,后端校验才是安全。
2. SQL注入:MyBatis 的${}是定时炸弹
MyBatis 里#{}是预编译,安全;${}是字符串拼接,直接注入。很多人在模糊查询时图方便写like '%${keyword}%',或者动态排序order by ${column},结果攻击者传个1' or '1'='1就能拖库。JPA 里用@Query拼接字符串同样危险。
堵法:能用#{}就别用${}。模糊查询用concat('%', #{keyword}, '%')。动态排序必须用白名单校验,比如只允许create_time、id等固定字段,其他一律拒绝。永远不要相信用户输入能直接拼进 SQL。
3. 敏感信息泄露:返回全字段,日志打密码
接口直接返回User实体,把password、salt、idCard全吐给前端。或者日志里log.info("用户登录:{}", user),把密码明文打进日志文件。更隐蔽的是异常堆栈直接返回给前端,暴露数据库表名、框架版本,给攻击者送情报。
堵法:用 DTO/VO 返回,只暴露必要字段。密码等敏感字段用@JsonIgnore忽略。日志里严禁打印密码、token、身份证。全局异常处理返回统一错误码和模糊提示,堆栈只进日志。别让接口成为信息泄露的帮凶。
4. CSRF:基于 Cookie 认证的隐形杀手
如果接口用 Session/Cookie 认证,攻击者诱导你点一个链接,就能以你的身份发请求。比如GET /api/transfer?to=hacker&amount=10000,你一点,钱就没了。SpringBoot 默认不防 CSRF,因为很多人用 JWT 无状态认证,但一旦用了 Cookie,就必须防。
堵法:如果必须用 Cookie,开启 Spring Security 的 CSRF 防护,前端请求带CSRF-TOKEN。更推荐用 JWT 放在Authorization头,天然免疫 CSRF。但 JWT 要设短过期时间,配合刷新 token,并且密钥不能硬编码在代码里。
5. 无限流防重放:接口被刷到崩
登录接口不做限流,攻击者用字典暴力破解;短信接口不限流,一条一块钱,一晚上能刷掉几万块;支付回调不做防重放,同一笔订单反复通知,导致重复发货。这些都不是危言耸听,而是真实事故。
堵法:用 Redis + Lua 做接口限流,按 IP 或用户维度限制 QPS。登录失败次数过多锁定账号。短信验证码 60 秒内只能发一次,且验证码只能用一次。支付回调必须验签,并用唯一订单号做幂等,处理过的回调直接返回成功,不再重复处理。防重放可以用时间戳 + nonce,服务端缓存 nonce 一段时间。
结语
接口安全不是“加个登录”就完事,它贯穿参数校验、权限控制、数据返回、日志记录、限流防重每一个环节。这5个漏洞,每一个都有人栽过跟头。堵上它们,你的 SpringBoot 接口才算真正上了锁。别等被薅光了才后悔,安全这件事,永远值得提前做。