接口安全概述:认证、授权、审计

做接口安全这么多年,我最深的体会是:安全不是加一把锁,而是一整套规则。你想想看,一个对外暴露的 API,每天几百上千万次调用,里面混着爬虫、恶意扫描、甚至数据盗取。怎么防?

说白了,就三个环节:认证、授权、审计。我习惯把它们叫做“接口安全的三道门”。

核心观点:认证解决“你是谁”,授权解决“你能干什么”,审计解决“你干了什么”。三件事缺一不可。

为什么这三件事必须分开?

我在项目中遇到过不少同学,把认证和授权混在一起搞。比如登录时顺便把用户角色塞进 ,然后直接用角色判断权限。看似省事,但你想想看——角色变了怎么办? 还没过期,旧权限还在用。这就是典型的边界没划清。

还有一种情况:接口只检查了 是否合法(认证),没检查这个用户有没有权限调用(授权)。结果普通用户通过抓包,直接调了管理员接口。嗯,很常见。

所以,三道门必须独立设计,逐一实现。下面我们一个一个来说。

认证(Authentication):确认身份

认证就是问:你谁啊?

常见的认证方式有这些:

认证方式典型实现安全性适用场景
HTTP Basic Auth用户名:密码 base64低(明文传输,需配合 HTTPS)内部工具、调试接口
/ JWT服务端签发 ,客户端携带中(注意签名算法和过期时间)RESTful API、移动端
OAuth2.0授权码流程、客户端凭证高(标准协议,支持第三方)开放平台、跨系统授权
+ Secret请求签名(HMAC)中高(防重放需加时间戳)服务端到服务端调用
一个小技巧:我个人习惯在 里只放用户 ID 和基础元数据(如签发时间、过期时间)。千万别把角色、权限直接塞进 —— 那会给授权留下死角。

授权(Authorization):控制行为

认证通过了,接下来问:你有资格做这件事吗?

授权需要依赖权限模型,最常见的就是我们这门课的核心 —— RBAC(基于角色的访问控制)。但这里先不展开 RBAC 的细节,我们先讲清楚授权的职责:

  • 根据用户身份,查询角色 / 权限列表
  • 判断当前请求的资源 + 操作,是否在权限范围内
  • 如果不在,直接返回 403 Forbidden

我曾经遇到一个坑:开发同学在授权逻辑里直接硬编码了“管理员角色 ID=1”。结果后来业务调整,角色表重排,ID 变了,管理员访问不了后台。嗯,从那时起我再也不在代码里写死角色 ID。

警惕:授权决策必须基于权限而非角色。角色只是权限的集合,角色可能变,权限集也可能变。用 RBAC 的核心是“角色-权限”分离,不是“角色直接当权限用”。

审计(Audit):留下痕迹

最后一道门,也是最容易被忽略的一道门:审计。

认证和授权都过了,用户正常访问接口。但你得知道:谁在什么时候做了什么操作?传了什么参数?结果成功还是失败?

审计要记录的关键字段,我一般这样设计:

字段说明示例
user_id操作者标识12345
action操作类型DELETE
resource操作对象/api/users/678
result执行结果success / fail
ip来源 IP192.168.1.1
timestamp操作时间2025-03-20T10:30:00Z
request_body请求参数(敏感信息脱敏){ "name": "***" }

你可能觉得审计就是个日志,用不上。但真遇到安全事件(比如数据泄露),审计日志就是唯一的破案线索。我在项目中见过一个案例:攻击者通过 SQL 注入拿到了管理员 ,公司因为没审计日志,花了三天才定位到漏洞入口。

最佳实践:审计日志写入专用存储(如 ELK、时序数据库),不要和业务日志混在一起。并且要设置保留周期,至少 180 天,合规要求高的行业建议 1 年以上。

三者关系图

下面这张图展示了认证、授权、审计在接口请求中的完整流程:

接口安全三大支柱:认证 → 授权 → 审计 客户端请求 认证 验证身份 授权 检查权限 审计 记录日志 返回 403 Forbidden 返回正常响应 审计日志存储(ES / 数据库)

从上图可以看出:所有请求先经过认证,认证通过后进入授权判断。如果授权失败直接返回 403,不再继续;如果授权成功,则执行接口逻辑,同时审计模块记录操作明细。

我的一些避坑建议

  • 认证和授权不能复用同样的代码路径。我曾经见过一个项目,认证和授权写在一个 filter 里,导致异常时既未正确身份校验,又遗漏了权限检查。
  • 审计日志不要只记录成功。失败的认证和授权同样要记 —— 它们是安全事件的前兆。
  • 注意敏感信息脱敏。审计日志里如果记录了明文密码或 ,那就变成新的安全漏洞了。
  • 授权失败不返回具体原因。你想想看,如果告诉用户“你没有删除权限”,攻击者就知道你的权限模型里有“删除”这个动作。统一返回 403 即可。
再说个实测技巧:在接口返回中,给审计日志加一个全局唯一 ID(trace_id)。这样当业务出问题时,可以直接用 trace_id 在日志系统里查到完整的操作链路。