如何解决在我的ASP中的iisreset之后出现的一个反forgerytoken异常。净MVC应用程序?

时间:2023-02-02 04:15:01

I’m having problems with the AntiForgeryToken in ASP.Net MVC. If I do an iisreset on my web server and a user continues with their session they get bounced to a login page. Not terrible but then the AntiForgery token blows up and the only way to get going again is to blow away the cookie on the browser.

我在ASP中遇到了反伪造令牌的问题。净MVC。如果我在我的web服务器上执行iisreset,用户继续他们的会话,他们就会跳转到登录页面。这并不可怕,但是反伪造标记会崩溃,唯一的方法是将浏览器上的cookie吹走。

With the beta version of version 1 it used to go wrong when reading the cookie back in for me so I used to scrub it before asking for a validation token but that was fixed when it was released.

在版本1的beta版本中,它在为我读取cookie时出现了错误,所以我以前在请求验证令牌之前会对它进行删除,但在发布时已经修复了。

For now I think I’ll roll back to my code that fixed the beta problem but I can’t help but think I’m missing something. Is there a simpler solution, heck should I just drop their helper and create a new one from scratch? I get the feeling that a lot of the problem is the fact that it’s tied so deeply into the old ASP.Net pipeline and is trying to kludge it into doing something it wasn’t really designed to do.

现在,我想回到我的代码,修复了测试版的问题,但我不得不认为我漏掉了什么。有更简单的解决方案吗?见鬼,我应该放弃他们的助手,从头创建一个新的吗?我有一种感觉,很多问题是它与旧的ASP有很深的联系。Net pipeline并试图将它组装起来,使其做一些并非真正设计用来做的事情。

I had a look in the source code for the ASP.Net MVC 2 RC and it doesn't look like the code has changed much so while I haven't tried it, I don't think there are any answers there.

我查看了ASP的源代码。Net MVC 2 RC看起来代码变化不大,所以虽然我还没试过,但我不认为有任何答案。

Here is the relevant part of the stack trace of the exception.

这里是异常堆栈跟踪的相关部分。

Edit: I just realised I didn't mention that this is just trying to insert the token on the GET request. This isn't the validation that occurs when you do a POST kicking off.

编辑:我刚意识到我没有提到这只是试图在GET请求中插入令牌。这不是当你做一个帖子开始时的验证。

System.Web.Mvc.HttpAntiForgeryException: A required anti-forgery token was not
supplied or was invalid.
---> System.Web.HttpException: Validation of viewstate MAC failed. If this 
application is hosted by a Web Farm or cluster, ensure that <machineKey> 
configuration specifies the same validationKey and validation algorithm. 
AutoGenerate cannot be used in a cluster.
---> System.Web.UI.ViewStateException: Invalid viewstate. 
  Client IP: 127.0.0.1
  Port: 4991
  User-Agent: scrubbed
  ViewState: scrubbed
  Referer: blah
  Path: /oursite/Account/Login
---> System.Security.Cryptography.CryptographicException: Padding is invalid and
cannot be removed.
at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
at System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, IVType ivType, Boolean useValidationSymAlgo)
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError)
at System.Web.UI.ViewStateException.ThrowMacValidationError(Exception inner, String persistedState)
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
at System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState)
at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken)
--- End of inner exception stack trace ---
at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken)
at System.Web.Mvc.HtmlHelper.GetAntiForgeryTokenAndSetCookie(String salt, String domain, String path)
at System.Web.Mvc.HtmlHelper.AntiForgeryToken(String salt, String domain, String path)

6 个解决方案

#1


40  

If your MachineKey is set to AutoGenerate, then your verification tokens, etc won't survive an application restart - ASP.NET will generate a new key when it starts up, and then won't be able to decrypt the tokens correctly.

如果您的MachineKey被设置为自动生成,那么您的验证令牌等将无法在应用程序重新启动- ASP中生存。NET将在启动时生成一个新密钥,然后不能正确地解密令牌。

If you are seeing this a lot, I'd suggest:

如果你经常看到这个,我建议:

  1. Configuring a static MachineKey (you should be able to do this at the application level), see "How to: Configure a MachineKey" for more information
  2. 配置静态MachineKey(您应该能够在应用程序级别上进行此操作),请参见“如何:配置MachineKey”以获得更多信息
  3. Try not to perform IIS Resets when the site is being used1
  4. 当站点被使用时,尽量不要执行IIS重置

1 The best way to do this is by having a loadbalanced application, which will require you to set a static MachineKey. Another option is to take the site down by placing a file named app_offline.htm in the root of the site, which will take the site offline and display your message - at least the users will expect things to go wrong.

最好的方法是使用loadbalanced应用程序,这将要求您设置一个静态MachineKey。另一个选项是通过放置一个名为app_offline的文件来关闭站点。htm位于站点的根,它将使站点离线并显示您的消息——至少用户会认为事情会出错。

#2


13  

For now I've gone with a solution that scrubs the cookie if the exception is thrown. If the exception is thrown again I'll just let it happen as it was.

现在,我使用了一个解决方案,如果抛出异常,它将清除cookie。如果再次抛出异常,我将让它按原样发生。

I won't mark this as 'the' answer for now in the hope that someone has a better answer.

我现在不会把这个标记为“答案”,希望有人有更好的答案。

public static class MyAntiForgeryExtensions
{
    // Methods
    public static string MyAntiForgeryToken(this HtmlHelper helper)
    {
        return MyAntiForgeryToken(helper, null);
    }

    public static string MyAntiForgeryToken(this HtmlHelper helper, string salt)
    {
        string fragment;
        string path = helper.ViewContext.HttpContext.Request.ApplicationPath;
        try
        {
            fragment = helper.AntiForgeryToken(salt, null, path);
        }
        catch (HttpAntiForgeryException)
        {
            // okay, scrub the cookie and have another go.
            string cookieName = GetAntiForgeryTokenName(path);
            helper.ViewContext.HttpContext.Request.Cookies.Remove(cookieName);
            fragment = helper.AntiForgeryToken(salt, null, path);
        }
        return fragment;
    }

    #region AntiForgeryData code that shouldn't be sealed
    // Copied from AntiForgeryData since they aren't accessible.
    internal static string GetAntiForgeryTokenName(string appPath) {
        if (String.IsNullOrEmpty(appPath)) {
            return "__RequestVerificationToken";
        }
        else {
            return "__RequestVerificationToken_" + Base64EncodeForCookieName(appPath);
        }
    }
    private static string Base64EncodeForCookieName(string s) {
        byte[] rawBytes = Encoding.UTF8.GetBytes(s);
        string base64String = Convert.ToBase64String(rawBytes);

        // replace base64-specific characters with characters that are safe for a cookie name
        return base64String.Replace('+', '.').Replace('/', '-').Replace('=', '_');
    }
    #endregion
}

#3


10  

i had this issue and to fix what you need to do is add an explicit machine key in your web-config...

我遇到了这个问题,为了解决这个问题,您需要在web配置中添加一个显式的机器键……

<machineKey validationKey="D82960E6B6E9B9029D4CAB2F597B5B4AF631E3C182670855D25FBDE1BFAFE19EFDE92ABBD1020FC1B2AE455D5B5F8D094325597CE1A7F8B15173407199C85A16" decryptionKey="577404C3A13F154908D7A5649EEC8D7C8A92C35A25A3EC078B426BB09D426A71" validation="SHA1" decryption="AES" /> 

ensure its placed in web.config within...

确保其放置在网络。配置在…

<system.web>

#4


7  

You can add AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; into global.asax

您可以添加AntiForgeryConfig。SuppressIdentityHeuristicChecks = true;到global.asax

protected void Application_Start() {
    AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
}

#5


4  

If I do an iisreset on my web server and a user continues with their session they get bounced to a login page.

如果我做一个iis重启web服务器和用户继续他们的会话会反弹到一个登录页面。

There's no reason an iisreset to bring the user to the login page. If you use cookies to track authentication information and have a stateless application, the user should stay authenticated even after a server reboot (of course if a request is made during the reset it will fail).

iisreset没有理由将用户带到登录页面。如果您使用cookie跟踪身份验证信息并拥有一个无状态应用程序,那么即使在服务器重新启动之后,用户也应该进行身份验证(当然,如果在重置过程中发出了请求,那么它将失败)。

#6


4  

Actually I found this to work in my logon action:

实际上,我发现这在我的登录行为中是有效的:

    public ActionResult LogOn()
    {
        formsAuthentication.SignOut();

        Response.Cookies.Clear();

        Session[SessionKeys.USER_SESSION_KEY] = null;
        Session.Clear();
        Session.Abandon();


        return View();
    }

The important part was : Response.Cookies.Clear();

最重要的部分是:Response.Cookies.Clear();

#1


40  

If your MachineKey is set to AutoGenerate, then your verification tokens, etc won't survive an application restart - ASP.NET will generate a new key when it starts up, and then won't be able to decrypt the tokens correctly.

如果您的MachineKey被设置为自动生成,那么您的验证令牌等将无法在应用程序重新启动- ASP中生存。NET将在启动时生成一个新密钥,然后不能正确地解密令牌。

If you are seeing this a lot, I'd suggest:

如果你经常看到这个,我建议:

  1. Configuring a static MachineKey (you should be able to do this at the application level), see "How to: Configure a MachineKey" for more information
  2. 配置静态MachineKey(您应该能够在应用程序级别上进行此操作),请参见“如何:配置MachineKey”以获得更多信息
  3. Try not to perform IIS Resets when the site is being used1
  4. 当站点被使用时,尽量不要执行IIS重置

1 The best way to do this is by having a loadbalanced application, which will require you to set a static MachineKey. Another option is to take the site down by placing a file named app_offline.htm in the root of the site, which will take the site offline and display your message - at least the users will expect things to go wrong.

最好的方法是使用loadbalanced应用程序,这将要求您设置一个静态MachineKey。另一个选项是通过放置一个名为app_offline的文件来关闭站点。htm位于站点的根,它将使站点离线并显示您的消息——至少用户会认为事情会出错。

#2


13  

For now I've gone with a solution that scrubs the cookie if the exception is thrown. If the exception is thrown again I'll just let it happen as it was.

现在,我使用了一个解决方案,如果抛出异常,它将清除cookie。如果再次抛出异常,我将让它按原样发生。

I won't mark this as 'the' answer for now in the hope that someone has a better answer.

我现在不会把这个标记为“答案”,希望有人有更好的答案。

public static class MyAntiForgeryExtensions
{
    // Methods
    public static string MyAntiForgeryToken(this HtmlHelper helper)
    {
        return MyAntiForgeryToken(helper, null);
    }

    public static string MyAntiForgeryToken(this HtmlHelper helper, string salt)
    {
        string fragment;
        string path = helper.ViewContext.HttpContext.Request.ApplicationPath;
        try
        {
            fragment = helper.AntiForgeryToken(salt, null, path);
        }
        catch (HttpAntiForgeryException)
        {
            // okay, scrub the cookie and have another go.
            string cookieName = GetAntiForgeryTokenName(path);
            helper.ViewContext.HttpContext.Request.Cookies.Remove(cookieName);
            fragment = helper.AntiForgeryToken(salt, null, path);
        }
        return fragment;
    }

    #region AntiForgeryData code that shouldn't be sealed
    // Copied from AntiForgeryData since they aren't accessible.
    internal static string GetAntiForgeryTokenName(string appPath) {
        if (String.IsNullOrEmpty(appPath)) {
            return "__RequestVerificationToken";
        }
        else {
            return "__RequestVerificationToken_" + Base64EncodeForCookieName(appPath);
        }
    }
    private static string Base64EncodeForCookieName(string s) {
        byte[] rawBytes = Encoding.UTF8.GetBytes(s);
        string base64String = Convert.ToBase64String(rawBytes);

        // replace base64-specific characters with characters that are safe for a cookie name
        return base64String.Replace('+', '.').Replace('/', '-').Replace('=', '_');
    }
    #endregion
}

#3


10  

i had this issue and to fix what you need to do is add an explicit machine key in your web-config...

我遇到了这个问题,为了解决这个问题,您需要在web配置中添加一个显式的机器键……

<machineKey validationKey="D82960E6B6E9B9029D4CAB2F597B5B4AF631E3C182670855D25FBDE1BFAFE19EFDE92ABBD1020FC1B2AE455D5B5F8D094325597CE1A7F8B15173407199C85A16" decryptionKey="577404C3A13F154908D7A5649EEC8D7C8A92C35A25A3EC078B426BB09D426A71" validation="SHA1" decryption="AES" /> 

ensure its placed in web.config within...

确保其放置在网络。配置在…

<system.web>

#4


7  

You can add AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; into global.asax

您可以添加AntiForgeryConfig。SuppressIdentityHeuristicChecks = true;到global.asax

protected void Application_Start() {
    AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
}

#5


4  

If I do an iisreset on my web server and a user continues with their session they get bounced to a login page.

如果我做一个iis重启web服务器和用户继续他们的会话会反弹到一个登录页面。

There's no reason an iisreset to bring the user to the login page. If you use cookies to track authentication information and have a stateless application, the user should stay authenticated even after a server reboot (of course if a request is made during the reset it will fail).

iisreset没有理由将用户带到登录页面。如果您使用cookie跟踪身份验证信息并拥有一个无状态应用程序,那么即使在服务器重新启动之后,用户也应该进行身份验证(当然,如果在重置过程中发出了请求,那么它将失败)。

#6


4  

Actually I found this to work in my logon action:

实际上,我发现这在我的登录行为中是有效的:

    public ActionResult LogOn()
    {
        formsAuthentication.SignOut();

        Response.Cookies.Clear();

        Session[SessionKeys.USER_SESSION_KEY] = null;
        Session.Clear();
        Session.Abandon();


        return View();
    }

The important part was : Response.Cookies.Clear();

最重要的部分是:Response.Cookies.Clear();