12

ここでは、2 つのフォーム ポストを持つシンプルな MVC3 アプリケーションを用意しています。CSRF 攻撃を保護するために、こちらのガイダンスに従って、両方の形式で antiforgerytoken html ヘルパーを使用しました。

ここに私の2つのモデルがあります:

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}


public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}

ここに私のhomeController.csがあります:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Index(User user)
    {
        if (ModelState.IsValid)
            return RedirectToAction("About");

        return View();
    }

    public ActionResult About()
    {
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult About(Employee employee)
    {
        if (ModelState.IsValid)
            return RedirectToAction("PageA");

        return View();
    }
}

ここに私のInex.cshtmlがあります:

@model MvcAntiforgeryToken.Models.User

@using (Html.BeginForm()) {

@Html.AntiForgeryToken()
<div>
    <fieldset>
        <legend>User Information</legend>

        <div class="editor-label">
            @Html.LabelFor(m => m.FirstName)
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(m => m.FirstName)
            @Html.ValidationMessageFor(m => m.FirstName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(m => m.LastName)
        </div>
        <div class="editor-field">
            @Html.PasswordFor(m => m.LastName)
            @Html.ValidationMessageFor(m => m.LastName)
        </div>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
</div>

}

ここに私のAbout.cshtmlがあります:

@model MvcAntiforgeryToken.Models.Employee

@using (Html.BeginForm()) {

@Html.AntiForgeryToken()
<div>
    <fieldset>
        <legend>Employee Information</legend>

        <div class="editor-label">
            @Html.LabelFor(m => m.Id)
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(m => m.Id)
            @Html.ValidationMessageFor(m => m.Id)
        </div>

        <div class="editor-label">
            @Html.LabelFor(m => m.Name)
        </div>
        <div class="editor-field">
            @Html.PasswordFor(m => m.Name)
            @Html.ValidationMessageFor(m => m.Name)
        </div>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
</div>

}

ホーム/インデックスの投稿:

when user visits Home/Index, application created " RequestVerificationToken_Lw " cookie with value "pG2/E00Q2DngYxs98f92x9qqrIvrh6zCT/+GGte67NFZLazKFlz++QqMSHpkZ08Qum9vsBCtq7O7MSzCawJkEa2/hdjrWoAcHlDWxxYRWKXm+OxPbqlRs609zam4fK7hReGEX3zf8YR4ltH3oYf4AZgt2mZV31ihRGShiZ7Oy9k="

隠しフォーム入力に続く

<input name="__RequestVerificationToken" type="hidden" value="B1KKzYEFEdINnuhy53MqqxHCHELPUd5pX3vRqYWz1+pkhBA6YGFvSVtXgSURkAn3yNwee3nrqDCMXB8MB0SWiUU3GuHnhH7+Qc1IQebJHoFJZR2CPXNOmUzINXbBWKZz+35pQQQXdiKptR3raLSoElfQi18ZC4Pr7xNREGIOM2A=" /> 

ホーム/概要の投稿:

when user visits Home/About, application created " RequestVerificationToken_Lw " cookie with value "pG2/E00Q2DngYxs98f92x9qqrIvrh6zCT/+GGte67NFZLazKFlz++QqMSHpkZ08Qum9vsBCtq7O7MSzCawJkEa2/hdjrWoAcHlDWxxYRWKXm+OxPbqlRs609zam4fK7hReGEX3zf8YR4ltH3oYf4AZgt2mZV31ihRGShiZ7Oy9k="

および次のフォーム入力

<input name="__RequestVerificationToken" type="hidden" value="UOCMATdy93A0230aBmRPv5F0xpJlI2urE5sJ4nxsTSWrsi9/xM5qhrxQ4I2vWIjvVrhkW8gSgmGFp7c4XPQUQG5myMGipTAr2/mi5od+Sz6IcfrF2FxwjfWMslt96BcMG6b9BjaGbgnClQOVTkjfHEMIptOYUCTSbVK61dWp5qI=" /> 

ここに私の質問があります:

  1. RequestVerificationToken_Lw」 Cookie の値が両方のフォームで同じなのはなぜですか? フォームの投稿ごとに再作成するべきではありませんか?

  2. RequestVerificationToken_Lw」Cookie 値と「__RequestVerificationToken」隠し入力値が異なるのはなぜですか?

ご回答ありがとうございます。

4

2 に答える 2

17

CSRF 攻撃ベクトルの考え方は次のとおりです。私は自分の Web サイトhttps://fake-domain-that-looks-like-a-bank.comに悪意のあるフォームを作成しました。あなたのサイトから HTML と CSS を取得したので、見た目はまったく同じです。私は有効な証明書とすべてのロゴのベルとホイッスルを持っています。今、私はユーザーをだまして自分のサイトにアクセスさせています。

ユーザーは通常のフォームを見て何かをします。ただし、入力の一部を置き換えてどこにも行かないようにし、隠しフィールドをいくつか追加して、ユーザーが(意図せずに)何をするかを制御するように'op=modifyしましたop=delete。彼のすべてのアクションは、彼の (有効な) 認証 Cookie によって支えられています。

これで、偽造防止トークンがユーザーを保護します。攻撃者として、彼の Cookie と一致する有効な非表示フィールドをフォームに追加できないからです。どうにかして彼の Cookie を読み取ることができれば、認証トークンを簡単に盗むことができます。

MVC では、偽造防止トークンはログオンしているユーザーの名前にバインドされます。FormsAuthenticationユーザー名の構造を使用して変更すると、既存の Cookie を持つすべてのユーザーが問題に遭遇します。補足: 一般的な問題は、2 つのアカウントを保持しているユーザーが に遭遇するAntiForgeryTokenExceptionsことです。これが有効な使用シナリオである場合は、それを処理することをお勧めします。

実際の質問に対処するには:

Cookie が変更されない理由

リクエストごとに Cookie の値が変わると、マルチタブ ブラウジングが問題になります。

Cookie とフォームの値が異なる理由

MVC の Cookie には内部構造があるため、シリアル化されたバージョンは異なって見えます。内部にある実際のセキュリティ トークンは同一である必要があります。シリアライザーは、存在する情報 (ユーザー ID 名など) に応じて、さまざまな情報を格納します。バージョン バイト、これがセッション Cookie であるかどうかのインジケータなどもあります。

気骨のある詳細

詳細を知りたい場合は、http://aspnetwebstack.codeplex.com/を介してソースを複製しSystem.Web.WebPages\Helpers\AntiXsrf\TokenValidator.cs、他のファイルの中で を参照することをお勧めします。いずれにせよ、ソースを手元に置いておくと非常に役立ちます。

于 2013-02-04T16:32:46.010 に答える
0

明確な考えはありませんが、単一のセッションを通過する「RequestVerificationToken_Lw」には1つの値が必要だと思います。形ごとに新しい価値を生み出すわけではありません。

于 2013-01-22T08:25:39.183 に答える