ログインアクションをAntiforgeryToken属性で保護したい-トピックからの例外が発生する理由はわかっているが、適切な解決策を見つけることができないようです。
次のような状況があるとします。
それは午前8時です。アプリケーションユーザーは仕事に来て、座ってログインプロセスを開始します-現在のところ非常に可能一部のユーザーが同じものを取得するValidationToken。最初のログイン後、他のすべてのユーザーがログインしようとすると、上記の例外(または他のカスタム例外画面)が表示されます。
一部のユーザーがログインし、誤って "back"ボタンを押して再度ログインしようとしました-これはほとんどありませんが、発生する可能性があり、ユーザーが例外を表示したくない場合。
質問は簡単です-上記の状況を防ぐ方法、またはユーザーが何も気付かないようにそれらを処理する方法。私は以下を試しました:
現在、私はアクション本文のトークンを手動で検証するを考えてエラーをキャッチし、匿名ユーザーが試行したかどうかを確認しています:
public ActionResult SomeAction()
{
try
{
AntiForgery.Validate();
}
catch(HttpAntiForgeryException ex)
{
if(String.IsNullOrEmpty(HttpContext.User.Identity.Name))
{
throw;
}
}
//Rest of action body here
//..
//..
}
上記はエラーを防ぐようです-しかし、それは安全ですか?他にどんな選択肢がありますか?
前もって感謝します。
宜しくお願いします。
編集:
最後の「解決策」は、ログインフォームでのトークン検証を無効にすることでした。それを処理するより良い方法があるかもしれませんが、私が見つけたすべての解決策は、上記で提案した私のような醜い回避策だったようです。
これらの選択肢がどれほど「安全」であるかを知る方法がないため(それらがまったく安全である場合)、ログイン時にトークン検証を無効にすることを決定しました。
(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要素認証を要求します。セキュリティルーターの動作とほぼ同じです。しかし、あなたがそれをあなたのログインページに保持したいのであれば、あなたがフレンドリーなエラーページを設定している限り、私は問題を見ることはありません。