Is it possible to tell IIS to treat all old cookie

2019-04-16 17:49发布

问题:

We are using WIF authentication, and we have an issue that pops up on occassion where a users cookie gets in a bad state. The exception that gets thrown is:

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)

A quick fix for this is to clear your cookies or open in another browser or open in private/incognito mode. But ideally we can tell IIS to treat all cookies older than now as expired. This will force re-authentication, and everyone can continue on their merry way. Recycling the app-pool does not help.

Ideas?

EDIT: I can't say for sure, but I think most of the time we see this problem is when we have had to reboot the server.

回答1:

We are using this here

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
}