You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

更换依赖方应用池用户后WSFederation报密钥状态无效异常

问题:更换依赖方应用池身份后Cookie解密失败(CryptographicException)

我接手了一台运行.NET 4.7.2的STS服务器,它使用System.IdentityModel WSFederation基于主体颁发令牌,并通过SessionAuthenticationModule将令牌保存为Cookie。STS与依赖方均部署在Server 2016系统的IIS 10上,原本运行正常,但在更换依赖方应用池的运行身份后,出现如下错误:

[CryptographicException: Key not valid for use in specified state.
]
   System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope) +470
   System.IdentityModel.ProtectedDataCookieTransform.Decode(Byte[] encoded) +48

[InvalidOperationException: ID1073: A CryptographicException occurred when attempting to decrypt the cookie using the ProtectedData API (see inner exception for details). If you are using IIS 7.5, this could be due to the loadUserProfile setting on the Application Pool being set to false. ]
   System.IdentityModel.ProtectedDataCookieTransform.Decode(Byte[] encoded) +358
   System.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound) +191
   System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver) +824
   System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver) +86
   System.IdentityModel.Services.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie) +567
   System.IdentityModel.Services.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken) +306
   System.IdentityModel.Services.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs) +158
   System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +223
   System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +220
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +94

看起来依赖方无法解密Cookie,但为何Cookie解密会与应用池运行身份绑定?我已将新身份设为服务器管理员以排除权限问题,是否要求STS与所有依赖方使用相同运行用户?


原因分析与解决方案

解密与应用池身份绑定的核心原因

默认情况下,ProtectedDataCookieTransform使用DataProtectionScope.CurrentUser加密/解密Cookie。这个Windows DPAPI机制依赖于当前用户配置文件中的专属加密密钥——每个用户的密钥完全独立,用用户A加密的数据,只有用户A能解密。你更换了依赖方应用池的运行身份,相当于用新用户的密钥去解密旧用户加密的Cookie,密钥不匹配就会抛出Key not valid for use in specified state异常。

是否要求STS与依赖方用相同运行用户?

不需要强制使用同一用户,但必须保证加密/解密的密钥一致。以下是几种可行方案:

方案1:改用机器级DPAPI保护范围

修改STS和所有依赖方的配置,让Cookie加密使用DataProtectionScope.LocalMachine(机器级密钥)。同一台机器上的所有应用,不管应用池身份是谁,都能使用机器密钥解密。

  • 首先自定义ProtectedDataCookieTransform子类,指定机器级范围:
public class MachineProtectedDataCookieTransform : ProtectedDataCookieTransform
{
    public MachineProtectedDataCookieTransform() : base(DataProtectionScope.LocalMachine)
    {
    }
}
  • 然后在web.config中替换默认的转换类型:
<system.identityModel>
  <identityConfiguration>
    <securityTokenHandlers>
      <add type="System.IdentityModel.Services.Tokens.SessionSecurityTokenHandler, System.IdentityModel.Services">
        <sessionTokenRequirement>
          <cookieHandler mode="Default">
            <protection>All</protection>
            <transforms>
              <clear />
              <add type="YourNamespace.MachineProtectedDataCookieTransform, YourAssembly" />
            </transforms>
          </cookieHandler>
        </sessionTokenRequirement>
      </add>
    </securityTokenHandlers>
  </identityConfiguration>
</system.identityModel>

方案2:使用共享对称密钥加密

放弃DPAPI,改用统一的共享对称密钥来加密Cookie。STS和所有依赖方必须使用完全相同的密钥。

  • 在web.config中配置加密转换和共享密钥:
<system.identityModel>
  <identityConfiguration>
    <securityTokenHandlers>
      <add type="System.IdentityModel.Services.Tokens.SessionSecurityTokenHandler, System.IdentityModel.Services">
        <sessionTokenRequirement>
          <cookieHandler mode="Default">
            <protection>All</protection>
            <transforms>
              <clear />
              <add type="System.IdentityModel.Tokens.DeflateCookieTransform, System.IdentityModel" />
              <add type="System.IdentityModel.Tokens.SignedXmlCookieTransform, System.IdentityModel" />
              <add type="System.IdentityModel.Tokens.EncryptedXmlCookieTransform, System.IdentityModel" />
            </transforms>
          </cookieHandler>
        </sessionTokenRequirement>
        <securityTokenSerializer>
          <securityTokenHandlerConfiguration>
            <serviceTokenResolver>
              <add key="SharedEncryptionKey" value="你的Base64编码共享密钥" />
            </serviceTokenResolver>
          </securityTokenHandlerConfiguration>
        </securityTokenSerializer>
      </add>
    </securityTokenHandlers>
  </identityConfiguration>
</system.identityModel>

注意:密钥要妥善保管,避免泄露。

方案3:确保应用池加载用户配置文件

错误提示中提到的loadUserProfile设置,如果新应用池身份没有加载用户配置文件,DPAPI无法访问该用户的加密密钥。可以在IIS应用池高级设置中,将Load User Profile设为True。但这个方案只适用于STS和依赖方使用同一用户身份的场景,身份不同的话还是需要用前面两种方案。


内容的提问来源于stack exchange,提问作者hada

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 06:56:00