44

ASP.NetMVCのAntiForgeryTokenに問題があります。Webサーバーでiisresetを実行し、ユーザーがセッションを続行すると、ログインページにバウンスされます。ひどいことではありませんが、AntiForgeryトークンが爆発し、再び動作する唯一の方法は、ブラウザのCookieを吹き飛ばすことです。

バージョン1のベータ版では、Cookieを読み戻すときに問題が発生したため、検証トークンを要求する前にCookieをスクラブしていましたが、リリース時に修正されました。

今のところ、ベータ版の問題を修正したコードにロールバックすると思いますが、何かが足りないと思わずにはいられません。より簡単な解決策はありますか?彼らのヘルパーをドロップして、最初から新しいヘルパーを作成する必要がありますか?多くの問題は、古いASP.Netパイプラインに深く結びついていて、実際には設計されていないことを実行しようとしているという事実だと感じています。

ASP.Net MVC 2 RCのソースコードを調べましたが、コードがあまり変更されていないようですので、試していませんが、答えはないと思います。

例外のスタックトレースの関連部分は次のとおりです。

編集:これがGETリクエストにトークンを挿入しようとしているだけだとは言わなかったことに気づきました。これは、POSTキックオフを実行するときに発生する検証ではありません。

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)
4

6 に答える 6

44

MachineKeyがAutoGenerateに設定されている場合、検証トークンなどはアプリケーションの再起動後も存続しません。ASP.NETは起動時に新しいキーを生成し、トークンを正しく復号化できなくなります。

あなたがこれをたくさん見ているなら、私は提案するでしょう:

  1. 静的MachineKeyの構成(これはアプリケーションレベルで実行できるはずです)。詳細については、「方法:MachineKeyを構成する」を参照してください。
  2. サイトが使用されているときにIISリセットを実行しないようにしてください1

1これを行う最良の方法は、負荷分散アプリケーションを使用することです。これには、静的なMachineKeyを設定する必要があります。もう1つのオプションは、サイトapp_offline.htmのルートに名前が付けられたファイルを配置してサイトを停止することです。これにより、サイトがオフラインになり、メッセージが表示されます。少なくとも、ユーザーは問題が発生することを予期します。

于 2010-02-05T13:39:57.003 に答える
15

今のところ、例外がスローされた場合にCookieをスクラブするソリューションを使用しました。例外が再度スローされた場合は、そのまま発生させます。

誰かがより良い答えを持っていることを期待して、今のところこれを「答え」としてマークしません。

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
}
于 2010-02-05T11:27:59.697 に答える
11

私はこの問題を抱えていました、そしてあなたがする必要があることを修正することはあなたのweb-configに明示的なマシンキーを追加することです...

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

内のweb.configに配置されていることを確認してください...

<system.web>
于 2013-06-21T09:59:46.580 に答える
7

あなたはに追加することができAntiForgeryConfig.SuppressIdentityHeuristicChecks = true;ますglobal.asax

protected void Application_Start() {
    AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
}
于 2013-12-06T10:29:35.937 に答える
4

Webサーバーでiisresetを実行し、ユーザーがセッションを続行すると、ログインページにバウンスされます。

iisresetがユーザーをログインページに誘導する理由はありません。Cookieを使用して認証情報を追跡し、ステートレスアプリケーションを使用している場合、サーバーを再起動した後もユーザーは認証されたままである必要があります(もちろん、リセット中に要求が行われると失敗します)。

于 2010-02-05T10:50:26.383 に答える
4

実際、私はこれが私のログオンアクションで機能することを発見しました:

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

        Response.Cookies.Clear();

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


        return View();
    }

重要な部分は次のとおりです。Response.Cookies.Clear();

于 2010-03-27T18:26:20.223 に答える