ASP.NET Core v2如何验证Azure AD返回的OIDC JWT防篡改?
好问题!作为经常用ASP.NET Core和Azure AD集成的开发者,我来给你详细拆解这个验证机制,以及忽略验证的严重风险。
当你用AddOpenIdConnect和Azure AD建立OIDC连接时,框架会自动帮你完成一整套JWT验证流程,这些步骤默认都是开启的,不需要手动写额外代码:
签名验证:这是最核心的一步。框架会自动从Azure AD的OpenID配置端点(比如
https://login.microsoftonline.com/{你的租户ID}/v2.0/.well-known/openid-configuration)获取公钥集合(JWKS)。拿到公钥后,会用它来验证JWT的签名——只有Azure AD用对应的私钥签发的令牌,才能被这个公钥验证通过,确保令牌没有被篡改或伪造。核心声明有效性检查:
- 过期时间(
exp)与生效时间(nbf):验证令牌是否在有效期内,拒绝已过期或还未生效的令牌。 - 受众(
aud):确认令牌的受众是你的Web应用的Client ID,避免其他应用的合法令牌被非法复用在你的系统里。 - 签发者(
iss):校验令牌的签发者是Azure AD的合法租户端点(比如https://login.microsoftonline.com/{你的租户ID}/v2.0/),防止攻击者伪造来自其他非法签发方的令牌。 - Nonce验证:框架会在发起OIDC认证请求时自动生成一个随机的
nonce值,并存入会话。当Azure AD返回令牌时,会把这个nonce包含在JWT里,框架会验证两者是否一致,有效防止重放攻击。 - 签名算法校验:确保令牌使用的是安全的签名算法(比如RS256),拒绝使用弱算法(比如HS256,除非你手动配置了对称密钥)的令牌。
- 过期时间(
Azure AD特定验证:针对Azure AD签发的令牌,框架还会额外验证
tid(租户ID)是否和你配置的租户一致,确保令牌来自你指定的Azure AD租户;另外还会检查amr(认证方法参考)声明,确认用户是通过合法的认证方式(比如密码、MFA)登录的。
如果因为配置错误或者手动关闭了这些验证,你的应用会面临极其严重的安全风险:
- 权限提升攻击:攻击者可以篡改JWT里的身份声明(比如把
roles改成Admin),因为没有签名验证,应用会直接信任这个伪造的身份,让攻击者获得管理员权限。 - 重放攻击:攻击者截获用户的有效JWT后,重复发送给应用,只要没有验证
nonce或exp,就能冒充合法用户持续访问系统。 - 伪造令牌攻击:攻击者可以自行生成结构合法但签名无效的JWT,应用因为没有验证签名,会直接接受这个假令牌,完全绕过身份认证流程。
- 跨应用非法访问:其他Azure AD应用的合法令牌被拿到你的应用中使用,因为没有验证
aud声明,攻击者可以用其他应用的身份访问你的系统资源。 - 过期令牌滥用:已过期的JWT被攻击者继续使用,应用因为没有检查
exp时间,会继续认可这个失效的身份,导致认证机制完全失效。
需要强调的是,ASP.NET Core的AddOpenIdConnect和Azure AD集成时,这些验证默认都是强制开启的,除非你手动修改TokenValidationParameters来关闭某个验证项——一般情况下绝对不建议这么做,尤其是出于安全合规的要求,这些验证是必须保留的。
内容的提问来源于stack exchange,提问作者contactmatt

