2012-03-29 16 views
15

2つのWebロールインスタンスを持つWindows Azure(最新の2.x OSバージョン)上で動作するASP.NET MVC 2(.NET 4)アプリケーションがあります。静的マシンキーでもHttpAntiForgeryExceptionがランダムに発生するのはなぜですか?

我々はすべてのPOSTリクエストのためのMVCにより供給された偽造防止トークンを使用して、我々はweb.configファイル内の静的マシンキーを設定しているので、すべてが複数のマシンにして再起動して動作します。ケースの99.9%は完全に動作します。

毎日のようにして、しかし、我々はメッセージと共に、HttpAntiForgeryExceptionを記録し、「必要な偽造防止トークンが提供または無効でしたいませんでした。」

私はこの問題は、クッキーがブラウザで許可されていないかもしれないが、我々はそれを検証してきましたし、クッキーが有効になっていると、正しく前後に送信されて知っています。

エラーがブラウザの様々な発生し、明らかに彼らは、操作を繰り返す必要があり、または、彼らはいくつかのデータを失うことができるので、ユーザーに問題が発生します。問題をローカルで再現することはできませんでしたが、Windows Azureでのみ発生します。

どうしてですか?どうすればそれを避けることができますか?

+0

(MVCチームの)セキュリティ担当者に確認したところ、おそらくダーリンが正しいと思われます。ユーザー名はおそらく変更されました。 – RickAndMSFT

答えて

0

あなたが試みることができる何のためのオプションがいくつかあります。マシンにリモーティングし、イベントログを見て、どこから起こったのかについてより多くの情報を得ることができるかどうかを調べることができます。それでも問題が解決しない場合は、DebugDiagまたは他のツールを使用してプロセスのダンプをキャプチャできます(この特定の例外が発生した時点でDebugDiagでキャプチャできます)。そしてそれを見て、何が起こっているのか見てみましょう。

あなたはそこからそれを把握するように見えることができない場合、あなたは常にあなたがそれを調査するために役立つマイクロソフトとサポートケースを作成することができます。

7

偽造防止トークンには、現在接続されているユーザのユーザ名が含まれています。そして、その妥当性を検証するとき、現在接続されているユーザーは、トークンが発行されたときに使用されたユーザーと照合されます。たとえば、ユーザーがまだ認証されておらず、偽造防止トークンを発行しているフォームがある場合は、そこにユーザー名が格納されません。ユーザーを認証するフォームを送信すると、トークンはもはや有効ではなくなります。ログアウトにも同じことが適用されます。

ここのようにValidateメソッドがどのように見えるかです:これをデバッグする1つの可能な方法は、そのソースコードからASP.NET MVCを再コンパイルし、例外あなたが入力したかの例ここで正確にログインすることです

public void Validate(HttpContextBase context, string salt) 
{ 
    string antiForgeryTokenName = AntiForgeryData.GetAntiForgeryTokenName(null); 
    string str2 = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath); 
    HttpCookie cookie = context.Request.Cookies[str2]; 
    if ((cookie == null) || string.IsNullOrEmpty(cookie.Value)) 
    { 
     throw CreateValidationException(); 
    } 
    AntiForgeryData data = this.Serializer.Deserialize(cookie.Value); 
    string str3 = context.Request.Form[antiForgeryTokenName]; 
    if (string.IsNullOrEmpty(str3)) 
    { 
     throw CreateValidationException(); 
    } 
    AntiForgeryData data2 = this.Serializer.Deserialize(str3); 
    if (!string.Equals(data.Value, data2.Value, StringComparison.Ordinal)) 
    { 
     throw CreateValidationException(); 
    } 
    string username = AntiForgeryData.GetUsername(context.User); 
    if (!string.Equals(data2.Username, username, StringComparison.OrdinalIgnoreCase)) 
    { 
     throw CreateValidationException(); 
    } 
    if (!string.Equals(salt ?? string.Empty, data2.Salt, StringComparison.Ordinal)) 
    { 
     throw CreateValidationException(); 
    } 
} 

スローされます。

+0

ASP.NET MVCチームのセキュリティ管理者が同意すると、ユーザー名が変更された可能性があります。 MVCはオープンソースなので、診断的なブランチを構築することができます。 AFトークンにはユーザー名は含まれていません。コードは、ユーザー名がフォームトークンであり、クッキートークンではないことを示しています。 – RickAndMSFT

+0

問題は、私たちはASP.NET認証を使用せず、ユーザ/アイデンティティを決して設定しないということです。ユーザー名は独自に変更できますか?(Azureのネットワークサービスとして実行されている場合) –

+0

ソースコードからASP.NET MVCを再コンパイルして、偽造防止の検証に失敗した場合はトレースしてみましたか? –

15

私は最近この問題に遭遇し、2つの原因が見つかりました。

1.ご使用のサーバーへのポストを行いキャッシュ可能な(すなわちantiforgeryがオンになります)であり、ユーザが自分を持っているページがある場合は、ブラウザが

をキャッシュされているページに対してオープンで最後のセッションを復元ブラウザは起動時に最後のセッションを復元するように設定されています(このオプションはクロムに存在します)。ページはキャッシュからレンダリングされます。ただし、リクエスト確認CookieはブラウザセッションCookieであり、ブラウザが閉じられたときに破棄されるため、リクエスト確認Cookieはそこに存在しません。クッキーがなくなるので、偽造防止の例外が発生します。解決策:ページがキャッシュされないようにレスポンスヘッダーを返します(つまり、キャッシュコントロール:プライベート、ストアなし)。

2。サイト開始時に複数のタブを開く場合のレース条件

ブラウザには起動時に一連のタブを開くオプションがあります。これらのうち2つ以上がサイトにアクセスしてリクエスト確認Cookieを返す場合は、リクエスト確認Cookieが上書きされる競合状態になる可能性があります。これは、リクエストの確認Cookieが設定されていないユーザーから複数のリクエストが送信された場合に発生します。最初のリクエストが処理され、リクエスト確認Cookieが設定されます。次に、2番目のリクエストは処理されますが、リクエスト時にまだ設定されていなかったクッキーは送信されないため、サーバは新しいリクエストを生成します。新しいものは最初のものを上書きし、次にそのページは次回投稿を実行するときに偽造防止の要求例外を取得します。 MVCフレームワークはこのシナリオを処理しません。このバグはマイクロソフトのMVCチームに報告されています。

+0

私は条件2も見ています。最初のユーザーにのみ発生します。最初のユーザーのためにページが読み込まれると、それ以上は発生しません。 – GnomeCubed

1

私はMVC3ウェブアプリケーションをいくつか持っています。クライアントの大半はPOST本体を送信しないためです。そして、これらのほとんどはIE8です。なぜなら、定期的なフォームの投稿に先行するajaxリクエストのバグがあるからです。ソートのそれは、クライアントのバグであることを証明している症状に対処するためと思われるIEの修正プログラムは、あまりにも便利なものとはいえ、ウェブの周りの問題についていくつかの議論があり

http://support.microsoft.com/?kbid=831167

これらのケースではありません、私は間違いなくいくつかの場所で提案し、「ソリューション」でキープアライブタイムアウト...

https://www.google.com/search?q=ie8+empty+post+body

と混乱についてないよ、私はへの種々の試みでそれを再現することができていたことがありません私は恐れているので、私は本当のことを持っていないので、POSTS間の接続をリセットIE空のPOSTボディの場合の解決策です。私たちが少し緩和したのは、ajaxでデータを取得するだけでPOSTメソッドを使用しないようにすることです。

完全なリクエストをログに記録する場合は、POST本体が空であるかどうかを確認し、そうであれば、おそらく古いIEになります。 Content-Length:0という意味ではありませんが、通常はヘッダーで正しいと思われるContent-Lengthがありますが、ヘッダーの後には何も表示されません。

完全なPOST本体がある場合でも、時折例外が発生するため、全体としての問題はまだ私にとって謎です。私たちのユーザ名は決して変更されず、私たちのキーも静的です。ソースにデバッグを追加しようとしませんでした。

0

私は自家製偽造防止コードでも同様の問題に遭遇しました。これは概念的にはMVCメカニズムに非常に似ています。最近のブラウザでは、非キャッシュとして指定されたページのキャッシュされたコピーを表示しようとしているため、問題が発生しているようです。

ページno-cacheディレクティブのすべての組み合わせを試しましたが、キャッシュされたページが表示されることがあります。

より良い解決策は、ページのonbeforeunloadイベントをフックし、DOMのトークン値を保持する非表示の入力フィールドの値を明示的にクリアすることです。

キャッシュされたページのコピーがロードされると、クリアされた入力フィールド値が含まれているように見えます。私は、ドキュメントレディ機能でこれをテストし、必要に応じてページをリロード:

window.location.reload(true); 

は非常に効果的に働くようだ、と私もMVC偽造防止コードのために、それがかもしれないと思います。