常见密钥类型及越权风险
大家好,我是老张。做安全攻防这些年,我见的最多的漏洞其实不是什么0day,而是密钥被盗用或越权。说白了,密钥就像你家门钥匙,丢一把就等于把整个房子敞开了。这一节我们掰开揉碎,聊聊最常见的几种密钥类型,以及它们身上那些「你没想到」的越权风险。
()
是最简单的身份凭证。一个字符串,放在 HTTP Header 里就能调用接口。很多团队图省事,直接把 Key 硬编码在代码里,或者用 GET 请求传参——我在项目中见过不少这样的案例。
举个例子。某电商平台为第三方开发者提供 。开发者申请了一个只读权限的 Key,但平台后端校验不严,用这个 Key 竟然能调用下单接口。这就是典型的「越权」——Key 本身没坏,但权限模型坏了。
我个人习惯把 分为三级:只读、读写、管理。每级都要和后端实现一一对应。另外,建议 Key 至少每90天轮换一次。我曾经在一个金融项目里发现,两年前的 还能用,吓得我连夜推了强制轮换策略。
| 风险场景 | 典型表现 | 我建议的防御 |
|---|---|---|
| 硬编码泄漏 | Key 出现在 Git 历史、日志、前端源码 | 使用密钥管理服务(Vault / KMS) |
| 权限过粗 | 一个 Key 拥有全部接口权限 | 拆分细粒度权限,每个 Key 绑定最小集合 |
| 无过期机制 | Key 永久有效 | 强制设置有效期,到期自动作废 |
JWT(JSON Web )
JWT 现在几乎是前后端分离的标准方案。一个 里包含了用户信息,服务器不用查数据库就能校验。听起来很美?但在实际项目中,JWT 的越权漏洞花样百出。
我印象最深的一次:某系统用 JWT 做身份认证,后端只验证了签名是否有效。攻击者把自己的 里的 userId 改成管理员 ID,重新签名后居然能访问后台所有接口。问题出在哪里?JWT 签名算法用的是 none——嗯,你没看错,有人把算法设成了 none,验签直接跳过。
// 攻击者伪造的 JWT —— 算法为 none
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VySWQiOiIxIn0.
// 后端解码后信任了 payload 中的 userId
规避这种问题,有几点必须做到:
- 强制要求签名算法为
HS256或RS256,并校验 algorithm 字段 - JWT 内部不要存放敏感数据,只放 userId 之类标识
- 设置合理的过期时间,一般建议 15-30 分钟
- 实现 黑名单,支持强制失效
OAuth 令牌
OAuth 协议本身很严谨,但实现往往走样。最常见的问题就是「scope 越权」——开发者申请了一个基础权限的授权码,结果后端在获取令牌时偷偷请求了更大的权限。
我记得帮一家创业公司做安全审计时发现,他们的 OAuth 流程根本没有校验 scope。用户授权了「读取邮件」,但服务器拿到令牌后竟然可以删除邮件。攻击者只要搞到一个合法的授权码,就能通过客户端篡改 scope 参数,让服务器发回一个高权限的 access 。
另外,refresh 也是个重灾区。有些项目把 refresh 的有效期设成一年甚至永久。我建议 refresh 不要超过7天,且在每次刷新后轮换旧的 refresh 。
SSH 密钥
SSH 密钥大家天天用。一对非对称密钥,公钥放服务器,私钥放本地,看起来挺安全的。但实际中,私钥泄漏、authorized_keys 权限混乱、Key 重用,都是越权的温床。
我做过一次渗透测试,目标公司所有服务器共用同一把 SSH 私钥。测试机上的私钥只给了开发组,但运维组某台机器的 /home 目录权限设成了 777…… 结果我从一台普通开发机器直接登录了生产环境的 root。这就是密钥重用 + 文件权限越权。
另一个常被忽视的点:ssh-agent 转发。当你从 A 机器 SSH 到 B 机器,再通过 B 机器 SSH 到 C 时,如果开启了 agent-forwarding,C 机器上的攻击者就能劫持你的私钥签名权限去登录其他机器。建议非必要不开启 ForwardAgent。
密钥越权风险全景图
下面这张图把四种密钥类型和它们最常见的越权路径串起来了。你可以把它当成安全检查清单。