web-dev-qa-db-ja.com

MVC5 AntiForgeryToken-「提供された偽造防止トークンはユーザー ""を対象としていましたが、現在のユーザーは "xxx"です。例外?

ログインアクションをAntiforgeryToken属性で保護したい-トピックからの例外が発生する理由はわかっているが、適切な解決策を見つけることができないようです。

次のような状況があるとします。

  1. それは午前8時です。アプリケーションユーザーは仕事に来て、座ってログインプロセスを開始します-現在のところ非常に可能一部のユーザーが同じものを取得するValidationToken。最初のログイン後、他のすべてのユーザーがログインしようとすると、上記の例外(または他のカスタム例外画面)が表示されます。

  2. 一部のユーザーがログインし、誤って "back"ボタンを押して再度ログインしようとしました-これはほとんどありませんが、発生する可能性があり、ユーザーが例外を表示したくない場合。

質問は簡単です-上記の状況を防ぐ方法、またはユーザーが何も気付かないようにそれらを処理する方法。私は以下を試しました:

  1. AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;を設定Application_Start in Global.asax-it 問題を修正していませんでも、同じ例外が発生します
  2. [OutputCache(NoStore = true、Duration = 0、VaryByParam = "None")][ValidateAntiForgeryToken]属性を持つメソッド-again、no幸運があります

現在、私はアクション本文のトークンを手動で検証するを考えてエラーをキャッチし、匿名ユーザーが試行したかどうかを確認しています:

public ActionResult SomeAction()
{
    try
    {
        AntiForgery.Validate();
    }
    catch(HttpAntiForgeryException ex)
    {
        if(String.IsNullOrEmpty(HttpContext.User.Identity.Name))
        {
            throw;
        }
    }

    //Rest of action body here
    //..
    //..
}

上記はエラーを防ぐようです-しかし、それは安全ですか?他にどんな選択肢がありますか?

前もって感謝します。

宜しくお願いします。

編集:

最後の「解決策」は、ログインフォームでのトークン検証を無効にすることでした。それを処理するより良い方法があるかもしれませんが、私が見つけたすべての解決策は、上記で提案した私のような醜い回避策だったようです。

これらの選択肢がどれほど「安全」であるかを知る方法がないため(それらがまったく安全である場合)、ログイン時にトークン検証を無効にすることを決定しました。

16
user2384366

(global.csで)設定してみてください:

_AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
_

これにより、名前識別子がトークンに追加されます。

二重ログインの問題については、スクリプトを使用して元の送信の日付と時刻を文書化し、同じトークンで2回目の送信を停止してみてください。

_// jQuery plugin to prevent double submission of forms
jQuery.fn.preventDoubleSubmission = function() {
  $(this).on('submit',function(e){
    var $form = $(this);

    if ($form.data('submitted') === true) {
      // Previously submitted - don't submit again
      e.preventDefault();
    } else {
      // Mark it so that the next submit can be ignored
      $form.data('submitted', true);
    }
  });

  // Keep chainability
  return this;
};
_

だから私たちは一つのことを知っています。ユーザーが[戻る]ボタンを好み、ダブルクリックする習慣がある場合、これはAntiforgeryTokenの大きな問題です。

しかし、あなたのアプリケーションが何をするかに依存して、そうすることへの彼らの強制を制限する方法があります。最も簡単なのは、訪問者がリクエストを変更するためにリクエストを「巻き戻す」必要があると感じさせないように最善を尽くすことです。

フォームのエラーメッセージが明確で簡潔であることを確認し、ユーザーが何が悪いのかを確実に把握できるようにします。 Contexualエラーはボーナスポイントを与えます。

フォーム送信の間は常にフォームの状態を維持します。パスワードやクレジットカード番号を除いて、MVCフォームヘルパーのおかげで言い訳はありません。 @Html.LabelFor(x => x.FirstName)

Angularまたはember.jsなどのSPAフレームワークで使用されるようなタブまたは非表示のdivにフォームが分散している場合は、スマートで、エラーが実際にフォームで発生したコントローラーレイアウトまたはフォームを表示するエラーを表示するときに送信します。ホームコントローラーや最初のタブに直接移動しないでください。

「何が起こっているのですか?」 -ユーザーに情報を提供し続ける

AntiForgeryTokenが検証しない場合、ウェブサイトはタイプSystem.Web.Mvc.HttpAntiForgeryExceptionの例外をスローします。

正しく設定した場合、フレンドリーエラーがオンになり、エラーページに例外が表示されず、正常なエラーページが表示され、エラーが発生したことがわかります。

少なくともHttpAntiForgeryExceptionをキャッチすることで、これらの例外を対象としたより有益なページをユーザーに提供することで、これを少し簡単にすることができます。

_private void Application_Error(object sender, EventArgs e)
{
    Exception ex = Server.GetLastError();

    if (ex is HttpAntiForgeryException)
    {
        Response.Clear();
        Server.ClearError(); //make sure you log the exception first
        Response.Redirect("/error/antiforgery", true);
    }
}
_

あなたの_/error/antiforgery_ビューはそれらを伝えることができます同じ情報を2回送信しようとしました

別のアイデアは、エラーをログに記録して、ユーザーをログイン画面に戻すことです。

OnExceptionメソッドをオーバーライドするHandleAntiforgeryTokenErrorAttributeクラスを作成します。

HandleAntiforgeryTokenErrorAttribute.cs:

_public class HandleAntiforgeryTokenErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        filterContext.ExceptionHandled = true;
        filterContext.Result = new RedirectToRouteResult(
            new RouteValueDictionary(new { action = "Login", controller = "Account" }));
    }
}
_

グローバルフィルター:

_public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new HandleAntiforgeryTokenErrorAttribute()
            { ExceptionType = typeof(HttpAntiForgeryException) }
        );
    }
}
_

ログインはアプリケーションの重要な部分であるため、いくつかのツールを使用してすべての情報を記録します

NLog重要なアプリケーション例外(Web例外を含む)に関する一般的なログと電子メール。

ElmahWeb例外のフィルタリングおよび電子メール用。

EDIT:また、SafeFormと呼ばれるjQueryプラグインを確認することもできます。 リンク

編集:

私はこれについての議論の多くを見てきました、そして、主題に関する皆の意見は有効なポイントを持っています、私がそれをどう見るかはです( owasp.org から取られます)

クロスサイトリクエストフォージェリ(CSRF)は、エンドユーザーに、現在認証されているWebアプリケーションで不要なアクションを強制的に実行させる攻撃です、 CSRF攻撃は、データの盗難ではなく、特に状態変更要求を対象としています。偽造防止トークンは、「ログオンしているユーザー」に固有です。したがって、ログインしてから戻ると、古いトークンは無効になります

ここで、ユーザーのIPアドレスが変更された場合、2要素認証でアプリケーションの割り当てにログインするために認証済みIPアドレスも使用するため、クロスサイトリクエストフォージェリが機能している場合、ユーザーはIPアドレスと一致せず、2要素認証を要求します。セキュリティルーターの動作とほぼ同じです。しかし、あなたがそれをあなたのログインページに保持したいのであれば、あなたがフレンドリーなエラーページを設定している限り、私は問題を見ることはありません。

20
pool pro