2017-01-28 21 views
5

基本的には、MVCアプリケーションの一部であるWeb APIコントローラでCross Site Request Forgeryから保護する必要があります。私はどんなアイディアにもオープンしています。この時点で、JavaScript API用のArcGISを使用してEsriマップを表示するMVCビューがあります。ユーザーは地図上にルートを作成し、それが交差するルートとさまざまな機能をAJAX POST経由で保存することができます。ビューにはフォームがありません。これは、サーバーにPOSTするすべてのデータがメモリにあり、画面(または非表示のフィールド)に表示されないためです。Web APIコントローラとCSRFへのAJAX POST

だから、私はantiforgeryトークンを取得するために私のMVCビューで、次があります。

@functions{ 
public string GetTokenHeaderValue() 
{ 
    string cookieToken, formToken; 
    AntiForgery.GetTokens(null, out cookieToken, out formToken); 
    return cookieToken + ":" + formToken; 
} 
} 

私はビューで、この隠された入力を持っていたが、それは「形式のトークン」との両方を持っているので、これは悪いです実現しましたAntiForgery.Validationで使用されるクッキーのトークンは:

<input type="hidden" id="antiforgeryToken" value="@GetTokenHeaderValue()" /> 

はその後、別のJavaScriptファイル(ビュー内のスクリプトタグではありません)、私は私のウェブAPIコントローラへのHTTP POSTをしています。私はリクエストヘッダにトークンを追加する場所です:

var headers = {}; 
headers['RequestVerificationToken'] = $("#antiforgeryToken").val(); 
// Ajax POST to Web API Controller 
$.ajax({ 
    async: true, 
    url: '/api/RouteData', 
    type: 'POST', 
    headers: headers, 
    data: requestData, 
    dataType: 'json', 
    error: function (xhr, statusText, errorThrown) { 
     console.log('Error saving route data! ' + errorThrown); 
    }, 
    success: function (result) { 
    } 
}); 

注:ページのためのArcGISを使用してのEsriマップを表示するので、体内に掲載取得されたデータは、(すべてのカスタムDojoウィジェットの内部メモリ内にありますJavaScript)。ユーザーがデータを入力していないので、ページ上のフォームはありません)

ウェブAPIコントローラにサーバー側ですべて一緒にそれを結びつける:。

[System.Web.Http.HttpPost] 
[ResponseType(typeof(RouteData))] 
public async Task<IHttpActionResult> PostRouteData(RouteDataViewModel routeDataVM) 
{ 
    try 
    { 
     HttpRequestMessage httpRequestMessage = HttpContext.Current.Items["MS_HttpRequestMessage"] as HttpRequestMessage; 
     ValidateRequestHeader(httpRequestMessage); 
    } 
    catch (Exception ex) 
    { 
     _logger.Log(LogLevel.Error, ex, ex.Message); 
     throw; 
    } 
     // Now that we know user is who they say they are, perform update 
} 

void ValidateRequestHeader(HttpRequestMessage request) 
{ 
    string cookieToken = ""; 
    string formToken = ""; 

    IEnumerable<string> tokenHeaders; 
    if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders)) 
    { 
     string[] tokens = tokenHeaders.First().Split(':'); 
     if (tokens.Length == 2) 
     { 
      cookieToken = tokens[0].Trim(); 
      formToken = tokens[1].Trim(); 
     } 
    } 
    AntiForgery.Validate(cookieToken, formToken); 
} 

AntiForgery.Validateが検証するものですトークン。

これは私にいくつかのアイデアを与えてくれたが、私の問題をかなり解決していないこの投稿(http://stackoverflow.com/questions/4074199/jquery-ajax-calls-and-the-html-antiforgerytoken/12116344#12116344 for more possible solutions)を参照してください。多くのクレジットはasp.netのこのポストにも起因します:https://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks

JavaScriptが別ファイルになっていて、サーバ側のRazor関数を呼び出して偽造防止トークンを取得できないというのは、私にとっては違う点です(私はそう思います)。フォームなしでCSRFを守る方法に関するアイデアはありますか?

答えて

2

CSRF保護は、クロスサイト要求偽造から保護するために、厳密にそれを行うために制定すべきものです。

quick overview of CSRFはこれです:

クロスサイトリクエストフォージェリ(CSRF)は、彼らが現在認証されていているWebアプリケーション上で不要なアクションを実行するためのエンドユーザーを強制的攻撃です。 CSRF攻撃は、攻撃者が偽造された要求への応答を見る方法がないため、データの盗難ではなく状態変更要求を対象としています。ソーシャルエンジニアリング(電子メールやチャットによるリンクの送信など)の助けを借りて、攻撃者はWebアプリケーションのユーザーを騙して、攻撃者が選択したアクションを実行する可能性があります。

それが保護されていない場合は、あなたのWeb APIに対するCSRF攻撃の例のようになり、次の

<form action="http://yourapi.com/api/DeleteAccount"> 
    <input type="text" name="id" /> 
    <input type="submit" /> 
</form> 

あなたが使用して、Web APIにログインした場合、侵害されたWebサイトからこのフォームを掲示することにより、クッキー認証(例として)を管理者アカウントとして使用すると、システムからアカウントを削除できる可能性があります。

これは、APIにリダイレクトされたときにブラウザがyourapi.comドメインに格納されているCookieを通過しているため、ユーザーを認証して必要な操作を実行するためです。この攻撃ベクトルは、サードパーティがこのトークンを知らないため、ベアラトークンなどを使用してAPIで認証する方法とは異なります。

偽造防止トークンを使用すると、偽造防止トークンを使用して、Webレスポンスでクライアントに送信された生成トークンとして保護され、クライアントによってバックアップされ、私たちが期待しているどこからでも許可された要求であることを確認してください。ベアラトークンと同様に、サードパーティは、サーバーからのリクエストで送信したトークンについて知らない可能性があります。この点で、あなたが実装したものは絶対的に正しいものであり、クライアントにトークンを渡すことは、それが動作することを期待するだけです。 ASP.NET MVC(サンセリフAPI)で

これは、次のように実装されています

<form .. /> 
    @Html.AntiForgeryToken() 
</form> 

...として、サーバー側の検証:あなたは@Html.AntiForgeryToken()を呼び出すときに両方のセット、

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Action(MyModel model) 
{ 
    // .. 
} 

方法をクッキー(クッキートークンを含む)をクライアントに送信し、<input type="hidden" ..>タグを生成してクライアントに送信します。これらは両方ともバックアップされ、検証されたサーバー側に送信されます。

その知識を武器に、あなたはこれがとにかく何が起こるかであるとして、「クッキー・トークン」と「フォーム・トークン」の両方の送信について、あなたの懸念は根拠がないことがわかります。

私は心配のためのあなたの原因を参照してください、しかし、何を軽減しようとしているのは中東(のMitM)攻撃ではなく、CSRFで男のように見えます。 MitM攻撃の大部分を回避するには、サイト/ APIの両方がHTTPS上で実行されていることを確認する必要があります。クライアントが依然としてMitM攻撃の影響を受けやすい場合、APIはおそらく攻撃者の心配がほとんどありません。

+1

あなたの説明は非常に役に立ち、徹底的です。私はHtml.AntiForgeryTokenのMVCの使用を中心に私の心をラップすることができましたが、私は実際にための方法がトークンで使用していることを少し異なるアプローチのAntiForgery.GetTokensを使用しているときから保護されたものへと混同ました。 – iCode

+1

問題ありませんが@iCode - あなたのWeb APIとMVCアプリケーションが同じドメイン上にある場合、あなたはまだ使用していない '@ Html.AntiForgeryToken()'とJSを経由して、フォーム・トークンを抜くことができ、当然のクッキートークン意志は時に送信されそのドメインに対するクッキーの性質上、次のリクエスト。詳細はあなたのリンクされた答えからです:http://stackoverflow.com/a/4074289/698179 –

+1

ああ、はい。私のWeb APIとMVCアプリケーションは同じドメインにあります。今私は私の理解で完全な円になった。実際、フォームトークンとクッキー(クッキートークンを含む)を生成する目的のために単純なフォームを作成することができました。その場合、JSを使用してAJAXポストのデータパラメータにフォームトークンを挿入します。これは、すでにPOSTにデータとして設定しているJSONオブジェクトに加えて追加することができます。私は両方の方法を学ぶためにそれをテストします。 – iCode

1

他の人といくつかの議論の後、私が実装したソリューションは実際には問題ないようです。はい、どちらのトークンも隠れた入力フィールドにあります。しかし、CSRFが守ろうとしている本質によって、もう1つサイトがあなたの代わりにPOSTしようとしています。このソリューションはうまくいきます。私が自分のサイトにいて、認証されていて、自分の代わりにPOSTをしようとする別のサイトを参照すると、サイトは必要なトークンを持っていません。

関連する問題