web-dev-qa-db-ja.com

偽造防止トークンの問題のトラブルシューティング

偽造防止トークンエラーが常に発生するフォームポストがあります。

私のフォームは次のとおりです。

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.EditorFor(m => m.Email)
    @Html.EditorFor(m => m.Birthday)
    <p>
        <input type="submit" id="Go" value="Go" />
    </p>
}

これが私のアクションメソッドです。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Join(JoinViewModel model)
{
    //a bunch of stuff here but it doesn't matter because it's not making it here
}

Web.configのmachineKeyは次のとおりです。

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

そして、ここに私が得るエラーがあります:

A required anti-forgery token was not supplied or was invalid.

HttpContextでユーザーを変更するとトークンが無効になることを読みましたが、ここでは発生しません。結合アクションのHttpGetは、単にビューを返します。

[HttpGet]
public ActionResult Join()
{
    return this.View();
}

だから私は何が起こっているのか分かりません。私はあちこち検索しましたが、すべてがmachineKeyの変更(アプリのサイクル)またはユーザー/セッションの変更のいずれかであることを示唆しているようです。

他に何が起こっているのでしょうか?これをトラブルシューティングするにはどうすればよいですか?

34
Jerad Rose

Adamの助けを借りて、MVCソースをプロジェクトに追加しましたが、同じエラーが発生する多くのケースがあることがわかりました。

以下は、偽造防止トークンの検証に使用される方法です。

    public void Validate(HttpContextBase context, string salt) {
        Debug.Assert(context != null);

        string fieldName = AntiForgeryData.GetAntiForgeryTokenName(null);
        string cookieName = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath);

        HttpCookie cookie = context.Request.Cookies[cookieName];
        if (cookie == null || String.IsNullOrEmpty(cookie.Value)) {
            // error: cookie token is missing
            throw CreateValidationException();
        }
        AntiForgeryData cookieToken = Serializer.Deserialize(cookie.Value);

        string formValue = context.Request.Form[fieldName];
        if (String.IsNullOrEmpty(formValue)) {
            // error: form token is missing
            throw CreateValidationException();
        }
        AntiForgeryData formToken = Serializer.Deserialize(formValue);

        if (!String.Equals(cookieToken.Value, formToken.Value, StringComparison.Ordinal)) {
            // error: form token does not match cookie token
            throw CreateValidationException();
        }

        string currentUsername = AntiForgeryData.GetUsername(context.User);
        if (!String.Equals(formToken.Username, currentUsername, StringComparison.OrdinalIgnoreCase)) {
            // error: form token is not valid for this user
            // (don't care about cookie token)
            throw CreateValidationException();
        }

        if (!String.Equals(salt ?? String.Empty, formToken.Salt, StringComparison.Ordinal)) {
            // error: custom validation failed
            throw CreateValidationException();
        }
    }

私の問題は、IDユーザー名とフォームトークンのユーザー名を比較する条件です。私の場合、ユーザー名が設定されていません(1つはヌルで、もう1つは空の文字列でした)。

多くの人がこの同じシナリオに出くわすとは思いませんが、他の人がチェックされている根本的な条件を見るのに役立つことを願っています。

19
Jerad Rose

エラーをオンデマンドで取得できるのかどうかはわかりません-またはログに表示されていますが、いずれにしても偽造防止トークンエラーを保証する方法があります。

それを待つ...

  • ログアウトしていることを確認してから、ログインを入力してください
  • ログインボタンをダブルクリック
  • あなたが取得します:

提供された偽造防止トークンはユーザー「」を対象としていましたが、現在のユーザーは「[email protected]」です。

(今のところ、MVC4でこの正確なエラーメッセージが変更され、これは本質的に同じメッセージであると仮定します)。

まだすべてをダブルクリックしている人がたくさんいます-これは悪いです!私はちょうど目を覚ました後にこれを見つけたので、これがどのようにテストを通過したかは本当にわかりません。ダブルクリックする必要さえありません。ボタンが反応しない場合に2回クリックすると、このエラーが発生します。

検証属性を削除しました。私のサイトは常にSSLであり、リスクについてはあまり心配していません。今すぐ動作するために必要なだけです。別の解決策は、JavaScriptを使用してボタンを無効にすることです。

これは、MVC4初期インストールテンプレートで複製できます。

31
Simon_Weaver

AntiForgeryTokenは、ログインしているユーザー資格情報が変更されていないことも確認します。これらもCookieで暗号化されます。 global.asax.csファイルでAntiForgeryConfig.SuppressIdentityHeuristicChecks = trueを設定すると、これをオフにできます。

9
VahidN

二重フォーム送信を防ぐ必要があります。次のようなコードを使用して、このタイプの問題を防ぎます。

$('#loginForm').on('submit',function(e){
    var $form = $(this);

    if (!$form.data('submitted') && $form.valid()) {
      // mark it so that the next submit can be ignored
      $form.data('submitted', true);
      return;
    }

    // form is invalid or previously submitted - skip submit
    e.preventDefault();
});

または

$('#loginForm').submit(function () {
    $(this).find(':submit').attr('disabled', 'disabled'); 
});
8
Bohdan Lyzanets

@Html.AntiForgeryToken()が2回呼び出され、HTTP投稿ペイロードで偽造防止トークンがめちゃくちゃになるという問題が発生しました。

3
Greg B

送信ボタンを無効にする前に、フォームが有効であることを確認する必要があります。

<script type="text/javascript">
//prevent double form submission
$('form', '#loginForm').submit(function () {
    if ($(this).valid()) {
        $(this).find(':submit').attr('disabled', 'disabled');
    }
});
2
Pažout

1つのサーバーまたはWebファームにいますか?単一のサーバーの場合は、web.configのmachineKey要素をコメントアウトして、ベースの開始点として再試行します。変更?また、Cookieがクリアまたは期限切れになる理由を考えることができますか?Cookieが適切に機能するためにも必要です。

2

アプリケーションを新しいマシンに移行しなければならなかったときにも、これとまったく同じ問題が発生しました。このエラーが突然現れた理由を理解できませんでしたが、移行に何らかの関係があると確信したため、aspnet_reqsqlを介してデータベースの登録を調査し始めました。確かに同じような場所で答えを見つけました。私の旅でも、これを解決する2つの方法があることを発見しました。

  1. ASP.NETは、各アプリケーションの暗号化キーを自動的に生成し、HKCUレジストリハイブにキーを保存します。サーバーファームでアプリケーションを移行またはアクセスする場合、これらのキーは一致しないため、方法1は一意のマシンキーをweb.configに追加することです。マシンキーはIIS管理コンソールから生成し、web.configのセクションに追加できます。

    <のmachineKey validationKey = "DEBE0EEF2A779A4CAAC54EA51B9ACCDED506DA2A4BEBA88FA23AD8E7399C4A8B93A006ACC1D7FEAEE56A5571B5AB6D74819CFADB522FEEB101B4D0F97F4E91" decryptionKey = "7B1EF067E9C561EC2F4695578​​295EDD5EC454F0F61DBFDDADC2900B01A53D4" 検証= "SHA1" 解読= "AES" />

  2. 2番目の方法は、AspNet_RegIISとスイッチ-gaを使用するappPoolまたは-iを使用するすべてのアプリを通じて、ワーカープロセスのHKCUレジストリへのアクセスを許可することです。

aspnet_regiis -ga "IIS APPPOOL\app-pool-name"

どの方法を選択してもこの問題を解決する必要がありますが、私の考えでは、将来の移行とサーバーの変更のための最も堅牢な方法はweb.configの一意のキーになります。これにより、アプリがHKCUレジストリをオーバーライドすることに注意ハイブし、アプリケーションを実行し続けます。

1
Graham Walker

同様の問題が発生しました。私が得た:

The required anti-forgery form field "__RequestVerificationToken" is not present. 

興味深いのは、それをデバッグしてみたところ、コントローラーで見つけると予想される両方の場所でトークンを見たことです

var formField = HttpContext.Request.Params["__RequestVerificationToken"];
var cookie = System.Web.HttpContext.Current.Request.Cookies["__RequestVerificationToken"].Value;

現実には、私はここを見ていたはずです:

var formField = HttpContext.Request.Form["__RequestVerificationToken"];

Paramsにはフォームフィールドだけでなく、QueryString、Form、Cookies、ServerVariablesが含まれています。

赤いニシンが邪魔にならないようになったら、AntiForgeryTokenの形式が間違っていることがわかりました。

1
tony

私がこのエラーを引き起こしたもう1つの可能性のあるチェック:フォームの1つに2つの@Html.AntiForgeryToken()がありました。

それが削除されると、問題はなくなりました。

1
JensB

htmlエラーロガーは正しい行ではありません。

ページ内のすべての読み込み値がnullでないことを確認する必要があります。

0
Ali Rasouli