是否可以告诉 IIS 将所有旧 cookie 视为已过期? (加密异常)

Is it possible to tell IIS to treat all old cookies as expired? (CryptographicException)

我们正在使用 WIF 身份验证,我们遇到一个问题,该问题会在用户 cookie 处于错误状态时弹出。抛出的异常是:

System.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.Security.Cryptography.CryptographicException: Key not valid for use in specified state.

at System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope)
at System.IdentityModel.ProtectedDataCookieTransform.Decode(Byte[] encoded)
--- End of inner exception stack trace ---
at System.IdentityModel.ProtectedDataCookieTransform.Decode(Byte[] encoded)
at System.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound)
at System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver)
at System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver)
at System.IdentityModel.Services.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie)
at System.IdentityModel.Services.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken)
at System.IdentityModel.Services.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

快速解决此问题的方法是清除您的 cookie 或在其他浏览器中打开或以 private/incognito 模式打开。但理想情况下,我们可以告诉 IIS 将所有早于 now 的 cookie 视为已过期。这将强制重新验证,每个人都可以继续他们的快乐方式。回收应用程序池没有帮助。

想法?

编辑:我不能肯定地说,但我认为大多数时候我们看到这个问题是在我们不得不重新启动服务器时。

我们在这里使用这个

public class CryptographicErrorModule : IHttpModule
{
    /// <summary>
    /// You will need to configure this module in the Web.config file of your
    /// web and register it with IIS before being able to use it. For more information
    /// see the following link: http://go.microsoft.com/?linkid=8101007
    /// </summary>
    #region IHttpModule Members

    public void Dispose()
    {
        //clean-up code here.
    }

    public void Init(HttpApplication context)
    {
        context.Error += ContextOnError;
    }

    private void ContextOnError(object sender, EventArgs eventArgs)
    {
        var context = HttpContext.Current;
        if (context == null)
            return;

        var error = context.Server.GetLastError();
        var cryptoError = error as CryptographicException;

        if (cryptoError == null && error.InnerException is CryptographicException)
            cryptoError = error.InnerException as CryptographicException;

        if (cryptoError == null)
            return;

        if (context.Request.Cookies["CryptoErrorOccured"] != null)
            return;

        context.Response.Cookies.Clear();
        var cookieCount = context.Request.Cookies.Count;
        for (int i = 0; i < cookieCount; ++i)
        {
            var httpCookie = context.Request.Cookies[i];
            if (httpCookie != null)
            {
                var cookieKey = httpCookie.Name;    

                var cookie = new HttpCookie(cookieKey)
                {
                    Expires = DateTime.Now.AddDays(-1), 
                    Value = "",
                    Path = httpCookie.Path,
                    Domain = httpCookie.Domain,
                    Secure = httpCookie.Secure,
                    HttpOnly = httpCookie.HttpOnly
                };

                context.Response.Cookies.Add(cookie);
            }
        }

        var cryptoErrorCookie = new HttpCookie("CryptoErrorOccured", DateTime.UtcNow.ToString("G"))
        {
            Expires = DateTime.Now.AddMinutes(5)
        };

        context.Response.Cookies.Add(cryptoErrorCookie);
        context.Server.ClearError();
    }

    #endregion
}