生产环境的API里,HTTPS开了,密钥验了,代码也审了——安全团队的 checklist 全打勾。但打勾和安全是两件事。ByteByteGo 最近扒了一批真实案例,发现一个荒诞 pattern:认证(authentication)做得滴水不漏,授权(authorization)却像没上锁的后门。
打个比方。你住的小区门禁很严,刷卡才能进电梯。但刷卡之后,电梯不会检查你要去几层——18 楼的住户按 28 楼,门照开。这就是"认证通过,授权缺失"的经典现场。攻击者拿到合法凭证后,能遍历整个系统的资源,而日志里一切正常。
为什么授权比认证更难做对
认证是"你是谁",授权是"你能干什么"。前者有标准答案——密码、令牌、双因素,业界玩了几十年。后者是开放题:用户 A 能看自己的订单,能不能看同事的?管理员能删数据,能不能删审计日志?
ByteByteGo 的工程师举了个电商场景。订单查询接口 /orders/{orderId} 验证了 JWT 令牌的有效性,却跳过一步:这个令牌对应的 userId,和订单所属的 userId 匹配吗?跳过的代价是,改个 URL 参数就能看别人订单。这类漏洞在渗透测试里叫 IDOR(不安全的直接对象引用),2024 年 OWASP API 安全 Top 10 里排第一。
更隐蔽的是权限继承问题。微服务架构下,服务 A 调用服务 B,B 再调用 C。A 带着用户令牌来,B 转发给 C 时,是用用户身份还是服务身份?选错了,要么性能爆炸(每个请求都验用户),要么权限膨胀(服务拿到超集权限)。
策略选择:没有银弹,只有场景
ByteByteGo 把授权策略分了类。RBAC(基于角色的访问控制)适合组织架构清晰的企业后台——"财务能看报表"这种规则写死就行。但 SaaS 产品多租户场景下,ABAC(基于属性的访问控制)更灵活:租户 ID + 用户角色 + 资源标签,动态计算权限。
OAuth 2.0 的 scope 机制常被误用。开发者把 scope 当功能开关用,比如 read:orders 和 write:orders,却忽略了 scope 只管"能访问哪类资源",不管"能访问哪条具体记录"。后者得靠额外的策略引擎,比如 Open Policy Agent(开放策略代理),或者干脆在业务代码里硬编码校验逻辑。
API 网关能挡一部分,但挡不全。网关验令牌、限流量、记日志,可它不知道"订单 12345 属于谁"。这个信息在订单服务的数据库里,网关拿不到。所以授权校验必须下沉到业务层,网关只做第一道闸。
一个反直觉的观察
ByteByteGo 提到,很多团队把安全预算砸在 WAF(Web 应用防火墙)和漏洞扫描上,却舍不得给授权逻辑写单元测试。结果是:SQL 注入防住了,越权访问满地跑。授权漏洞的单元测试很难写——你得造一堆用户、角色、资源的数据组合,模拟"横向越权"和"纵向越权"两种攻击路径。
横向越权:用户 A 访问用户 B 的同级别资源。纵向越权:普通用户访问管理员资源。两种漏洞的测试用例完全不同,却共用同一套接口。没有自动化测试覆盖,回归时很容易漏。
文章末尾,ByteByteGo 的工程师留了个问题:你的 API 里,授权校验是在网关、服务层,还是数据库层?如果用户带着合法令牌请求了一条不存在的记录,你的系统返回 404 还是 403?这个细节能暴露很多架构假设。
热门跟贴