SessionSecurityTokenHandler 尝试使用 DPAPI 解密 RSA 加密 cookie 中的 SessionSecurityToken;为啥?

Posted

技术标签:

【中文标题】SessionSecurityTokenHandler 尝试使用 DPAPI 解密 RSA 加密 cookie 中的 SessionSecurityToken;为啥?【英文标题】:SessionSecurityTokenHandler trying to decrypt SessionSecurityToken in RSA-encrypted cookie using DPAPI; why?SessionSecurityTokenHandler 尝试使用 DPAPI 解密 RSA 加密 cookie 中的 SessionSecurityToken;为什么? 【发布时间】:2012-10-05 22:16:04 【问题描述】:

我在 MSDN 论坛、Dominic Baier 的博客和其他来源中读到 DPAPI 在 Azure 中无法开箱即用,并且在任何类型的网络农场场景中处理联合身份验证的一种方法是替换DPAPI 使用整个场中可用的私钥进行转换,例如使用 X509 证书的 RSA 加密。我在我的 Azure MVC 应用程序中采用了这种方法,并像这样配置了SessionSecurityTokenHandler

FederatedAuthentication.ServiceConfigurationCreated += (sender, args) =>
    
        var sessionTransforms = new List<CookieTransform>(new CookieTransform[]
            
                new DeflateCookieTransform(),
                new RsaEncryptionCookieTransform(args.ServiceConfiguration.ServiceCertificate),
                new RsaSignatureCookieTransform(args.ServiceConfiguration.ServiceCertificate)
            );
        var sessionHandler = new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());
        args.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);                    
    ;

使用此配置,我们能够从身份提供者接收令牌并发布使用这些转换加密的安全 cookie。在 Azure 模拟器中运行,一切正常。但是,在 Azure 环境中,我们在浏览器中间歇性地看到以下错误:

Key not valid for use in specified state.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.Security.Cryptography.CryptographicException: Key not valid for use in specified state.


Source Error: 

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace: 


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

[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. ]
   Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded) +433
   Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound) +189
   Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver) +862
   Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver) +109
   Microsoft.IdentityModel.Web.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie) +356
   Microsoft.IdentityModel.Web.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken) +123
   Microsoft.IdentityModel.Web.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs) +61
   System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +270

这似乎表明SessionSecurityTokenHandler 正在尝试使用 DPAPI 解密 cookie,但为什么呢?我上面不是配置为使用RSA吗?

【问题讨论】:

【参考方案1】:

请注意,您现在可以使用 MachineKeySessionSecurityTokenHandler 对跨网络场的会话令牌进行签名和加密。

要使用它,您需要删除默认的SessionSecurityTokenHandler 并在Web.config 中添加MachineKeySessionSecurityTokenHandler

<system.identityModel>
  <identityConfiguration>
    <securityTokenHandlers>
      <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      <add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    </securityTokenHandlers>
  </identityConfiguration>
</system.identityModel>

MachineKeySessionSecurityTokenHandler 使用在Web.config 中配置的机器密钥,因此您也需要添加它:

<system.web>
  <machineKey validationKey="..." decryptionKey="..." validation="SHA1" decryption="AES" />
</system.web>

在BrainThud看到这个问题

【讨论】:

好提示。我不确定这是否真的能比 RSA 方法购买任何东西,但我很高兴知道它是可用的。 我的机器密钥已经配置好了,所以这是一个可靠的解决方案。【参考方案2】:

好吧,经过大量搜索,我已经弄清楚了我的问题所在。在我设置ServiceConfigurationCreated 之前,我正在做一些配置导致访问FederatedAuthentication.ServiceConfiguration。 According to MSDN, “当 Web 应用程序中的第一个 HTTP 模块引用 ServiceConfiguration 时,会引发 ServiceConfigurationCreated 事件”。我将事件处理程序设置移动到 Application_Start 的顶部,一切正常,这意味着该事件(仅触发一次)在我设置事件处理程序之前触发。

希望这可以节省我将其运行到地面所花费的 4 个多小时。

【讨论】:

哇!接得好!你有我的! 很好!!!但是为什么你没有通过配置文件呢? blogs.msdn.com/b/distributedservices/archive/2012/10/29/… @antwood 是更合乎逻辑的设置方式。我认为它在Application_Start 处理程序中完成的原因是因为这样做的人没有意识到它可以在web.config 中完成,这不是我想要改变的问题(尽管它可能毕竟花了更少的时间)。

以上是关于SessionSecurityTokenHandler 尝试使用 DPAPI 解密 RSA 加密 cookie 中的 SessionSecurityToken;为啥?的主要内容,如果未能解决你的问题,请参考以下文章