2026-06-13 · architecture / security
【身份与访问控制工程】IAM 全景:为什么这是高价值赛道
从 2020 年 SolarWinds 到 2024 年 Okta 支持系统泄露,身份基础设施的安全失败反复证明一件事:IAM 不是 IT 支撑系统,而是安全架构的承重墙。本文建立现代 IAM 的全景地图——从认证协议、令牌体系、权限模型到身份治理与平台选型,给出 5 个贯穿全系列的核心问题。











在 OAuth 2.0 和 OIDC 的工程讨论中,“JWT”这个词被严重过载了。人们用它指代 JSON Web Token(RFC 7519)、JSON Web Signature(RFC 7515)、JSON Web Encryption(RFC 7516)三个不同的东西——有时候连什么签什么都搞不清楚。本系列第 02 篇(OIDC)中已经提到 ID Token 是一个 JWT,但 ID Token 的格式依赖于 JWS 的签名模型和 JWKS 的密钥分发模型。本文回到 JOSE(JSON Object Signing and Encryption)体系的基础层,把 JWT / JWS / JWE / JWK / JWKS 的关系一次讲清楚。
JOSE 体系由五个 RFC 构成,它们之间的关系是:
flowchart TD
JWK["JWK (RFC 7517)<br/>JSON Web Key<br/>密钥的 JSON 表示"] --> JWS["JWS (RFC 7515)<br/>JSON Web Signature<br/>签名+payload → 三段式结构"]
JWK --> JWE["JWE (RFC 7516)<br/>JSON Web Encryption<br/>加密 payload → 五段式结构"]
JWS --> JWT["JWT (RFC 7519)<br/>JSON Web Token<br/>定义 claims 语义<br/>body 可以是 JWS 或 JWE"]
JWE --> JWT
JWK --> JWKS["JWKS<br/>JSON Web Key Set<br/>密钥集合 + kid 索引"]
iss、sub、exp、iat、aud
等)。header.payload.signature。header.encrypted_key.iv.ciphertext.tag。kid 字段做索引。所以准确的说法是:ID Token 是一个 JWT,JWT 的实现形式通常是 JWS(签名)或嵌套 JWS 在 JWE 中(签名+加密)。
一个 JWS 的结构是
BASE64URL(Header).BASE64URL(Payload).BASE64URL(Signature):
// Header (解码后)
{
"alg": "RS256",
"typ": "JWT",
"kid": "2026-06-key-01"
}
// Payload (解码后 — JWT Claims Set)
{
"iss": "https://idp.example.com",
"sub": "user-12345",
"aud": "my-app",
"exp": 1718400000,
"iat": 1718396400,
"jti": "unique-token-id-abc123"
}
// Signature (二进制)
// = RSASSA-PKCS1-v1_5-SHA-256(
// BASE64URL(Header) + "." + BASE64URL(Payload),
// PrivateKey
// )签名字段覆盖 Header 和 Payload
两部分(包括中间的点号),所以 Header 中的 alg
字段本身也被签名了——如果攻击者修改 alg 为
none,签名就会变化,验签失败。
| 算法族 | alg 值 |
密钥类型 | 签名大小 | 使用场景 |
|---|---|---|---|---|
| HMAC | HS256, HS384,
HS512 |
对称密钥(共享 secret) | 32-64 bytes | 内部服务间(密钥分发简单) |
| RSA | RS256, RS384,
RS512 |
非对称密钥 | 256-512 bytes | 传统 PKI 部署(兼容性最好) |
| ECDSA | ES256, ES384,
ES512 |
非对称密钥(ECC) | 64-132 bytes | 签名体积小,验证速度快 |
| EdDSA | EdDSA |
非对称密钥(Ed25519) | 64 bytes | 现代选择,安全性好,签名/验证都极快 |
| None | none |
无 | 0 bytes | 仅在测试中使用,生产环境必须拒绝 |
选型建议:
ES256(ECDSA P-256 +
SHA-256):签名体积是 RS256 的
1/4,验证速度快约 3 倍(移动端和 IoT
设备上差距更大),安全性等价。EdDSA:使用 Ed25519
曲线,签名和验证都极快,没有 ECDSA 的 nonce 复用风险(nonce
复用会导致私钥泄露)。但截至 2026 年,并非所有 JWT 库和 IdP
都支持 EdDSA。HS256
只在内部服务间使用:共享密钥意味着任何持有密钥的方都可以签发有效
token——在微服务架构中这意味着”密钥泄露 =
全局失陷”。HS256 的密钥必须至少有 256 位(32
字节随机值)。一个常见的安全漏洞是用弱密码短语(如
“my-secret”)作为 HS256 的密钥——JWT
库不会阻止你,但它可以被暴力破解。工程陷阱 1:
alg: "none"攻击。如果 JWT 验证库没有显式限制允许的算法列表,攻击者可以构造{"alg": "none", "typ": "JWT"}的 Header,使其接受未签名的 token。验证库的正确配置是:显式指定允许的算法列表,默认为空,不信任 token 自身的alg声明。
kid(Key
ID)的作用当签名方有多个密钥(如正在进行密钥轮换),kid
让验证方知道用哪个公钥来验证签名。kid
是一个任意字符串——在 JWKS 端点中,它与 JWK
对象的 kid 字段对应:
{
"keys": [
{"kty": "EC", "kid": "2026-06-key-01", "crv": "P-256", "x": "...", "y": "..."},
{"kty": "EC", "kid": "2026-03-key-01", "crv": "P-256", "x": "...", "y": "..."}
]
}验证方从 JWS Header 取 kid,在 JWKS 中找对应
key,用该 key 验证签名。
JWE 解决的是”如果有人截获了 token,能不能读到里面的内容”。JWS 只提供完整性和来源认证——签名不隐藏 payload,任何人 Base64 解码就能读到 all claims。
JWE 用双层加密模型解决这个问题:
flowchart LR
CEK["Content Encryption Key (CEK)<br/>随机生成"] -->|"RSA/ECDH 加密"| EK["Encrypted Key"]
Plaintext -->|"AES-GCM 用 CEK 加密"| CT["Ciphertext + Auth Tag"]
encrypted_key。ciphertext +
authentication tag。五段式结构:BASE64URL(Header).BASE64URL(EncryptedKey).BASE64URL(IV).BASE64URL(Ciphertext).BASE64URL(AuthTag)
Header 中的 enc
字段指定内容加密算法——A128GCM、A256GCM、A128CBC-HS256
等。alg
字段指定密钥加密算法——RSA-OAEP-256、ECDH-ES+A256KW
等。
工程陷阱 2:JWE 的加密不替代 TLS。如果你在 HTTPS 连接中传输 JWE,看起来是”双重加密”,但 JWE 的真实价值在于端到端加密——token 经过多个中间节点(API Gateway、负载均衡器、日志系统)时,JWE 的加密保持闭态,而 HTTPS 在每个中间节点终止。如果你的服务不在高安全需求行业(如金融、医疗等法规明确要求端到端加密的领域),优先使用 JWS + HTTPS 的组合,复杂度更低。
一个 EC P-256 公钥的 JWK 表示:
{
"kty": "EC",
"kid": "2026-06-key-01",
"use": "sig",
"alg": "ES256",
"crv": "P-256",
"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"
}字段说明:
kty(Key
Type):EC、RSA、oct(对称密钥)。use(Public Key
Use):sig(签名)或
enc(加密)。一个 key 不应同时用于两者。alg:此 key 适用的算法。kid:密钥标识符——JWKS 中的索引键。密钥轮换是令牌安全中最容易被工程团队搁置的问题,但当密钥泄露时,轮换窗口的长度直接决定了受影响的令牌数量。
典型轮换模式:
时间线:
T+0: JWKS 包含 [key-01] (active)
T+30d: JWKS 包含 [key-01, key-02] (transition)
→ 用 key-02 签发新 token
→ 继续用 key-01 验证旧 token
T+31d: JWKS 包含 [key-02] (key-01 移除)
→ 所有 key-01 签发的 token 失效
轮换的核心策略:
RP 不应该每次验证 token 都去拉一次 JWKS——这会引入不必要的延迟、增加 OP 的负载、在 OP 不可用时导致认证全挂。正确的做法是设立本地缓存:
Cache-Control 和
Expires Header(如果 OP 提供)。kid
不在缓存中或签名不匹配),重新拉取 JWKS,只重试一次。工程陷阱 3:很多 JWT 库(包括早期版本的
jsonwebtokenfor Node.js、PyJWTfor Python)默认不验证kid的存在——它们尝试用 JWKS 中每一个 key 去验证签名。这在 key 数量少时能跑,但有两个问题:a) O(n) 的验证复杂度在 key 数量增长时变成性能问题,b) 攻击者可以构造不带kid的 token 来探测服务的行为。
JOSE 体系的核心不是格式本身,而是它在分布式身份系统中的角色分工:
生产环境的 JWT 使用建议: - 签名算法选
ES256(兼容性最好)或
EdDSA(安全性最好)。 - kid
必须有——它是密钥轮换的基础。 - exp 加
iat,Access Token 不超过 15 分钟。 -
验证时显式限定允许的 alg 列表(默认拒绝
none)。 - JWKS 缓存,带失效和重试策略。
上一篇:SCIM 与账号生命周期:开通、变更、离职自动化 下一篇:Session、Refresh Token 与吊销体系
把当前热点继续串成多页阅读,而不是停在单篇消费。
2026-06-13 · architecture / security
从 2020 年 SolarWinds 到 2024 年 Okta 支持系统泄露,身份基础设施的安全失败反复证明一件事:IAM 不是 IT 支撑系统,而是安全架构的承重墙。本文建立现代 IAM 的全景地图——从认证协议、令牌体系、权限模型到身份治理与平台选型,给出 5 个贯穿全系列的核心问题。
2026-06-13 · architecture / security
OIDC 是当下企业 SSO 的事实标准,但大多数实现只用了它 20% 的规范。本文从 OIDC 核心规范出发,拆解 Authorization Code Flow + PKCE 的完整交互、ID Token 的验证规则、Discovery 与 Dynamic Registration 的互操作性机制,以及 RP-Initiated Logout 和 Session Management 的工程实现细节。
2026-06-15 · architecture / security
JWT 的无状态设计带来了可扩展性,但让令牌吊销变成了系统性问题——签出去的 JWT 在到期之前全是活令牌。Refresh Token Rotation、Token Introspection、基于事件的吊销通知、撤销列表——这些机制构成了身份系统的'紧急刹车',各自的成本、延迟和覆盖范围完全不同。本文拆解四种吊销机制的工程权衡。
2026-06-12 · architecture / security
身份感知代理(IAP)是零信任架构中用户进入企业资源的唯一入口——它取代了 VPN 的'拨入内网'模型,把每个 HTTP 请求的认证和授权检查放在资源前面。本文拆解 IAP 协议层的完整请求流、JWT 验证的严格性要求、Header Injection 的安全陷阱,以及 Pomerium/oauth2-proxy/Cloudflare Access 的实现差异。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。