ASP.NET MVC で CSRF 対策

0 件のコメント

Webアプリケーションを開発するとよく見かける脆弱性に CSRF (Cross-Site Request Forgery、クロスサイトリクエストフォージェリ) があります。 簡単には「ユーザーが予期しない処理を実行させようとする攻撃」といったところでしょうか。 その対策の1つに「正規の操作が行われていることを示すトークンを記述、検証する方法」があります。 ここでは、CSRFの詳細は記載せず、 ASP.NET MVC において、トークンを用いた CSRF対策 を実装する実例をまとめてみました。

目次

注意すべき処理

基本的に読み取り、表示以外は CSRF の危険性がないか注意すべき処理だと思います。

注意すべき処理

  • データ作成/登録 (Create)
  • データ更新 (Update)
  • データ削除 (Delete)

"データ" の 具体例

  • アカウント
  • カート
  • 記事
  • 帳票
  • 伝票

これらは組み合わせで考えられるので、例えば「アカウント作成/登録」、「帳票更新」、「伝票削除」といった感じの処理において注意します。 ここで挙げている "データ" 例 は世の中で考えられる一部の事象なので、各開発においてあてはめてみてください。

CSRF対策 で利用する クラス、メソッド

CSRF対策で利用するクラス、メソッドは以下の2種類です。

  • HtmlHelper.AntiForgeryToken
  • ValidateAntiForgeryTokenAttribute

cshtml 上に HtmlHelper.AntiForgeryToken でトークンを埋め込み、 cs 上の ValidateAntiForgeryTokenAttribute でトークンを確認するように実装します。 これにより、予期しない経路から処理が割り込まれた時、トークンが存在しないので拒否できるようになります。

CSRF対策 の 実装例

今回は、アカウントの新規作成処理において、CSRF対策を施す例を載せます。 アカウント新規作成は /Account/Create で実行できるようにしたいと思います。

作成するファイルは以下に示す 4ファイル です。

  • AccountController.cs はビューの表示と登録処理(CSRF対策用のトークンを検証)を行います。
  • AccountModel.cs は新規アカウント作成で登録するデータモデルです。
  • Complete.cshtml は登録完了画面です。
  • Create.cshtml は登録画面(CSRF対策用のトークンを埋め込み)です。

CSRF対策 として重要な実装は Create.cshtml (トークンの埋め込み) と AccountController.cs (トークンの検証) になります。

AccountController.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
namespace WebApplication.Controllers
{
    using System.Web.Mvc;
    using WebApplication.Models;
 
    /// <summary>
    /// アカウントに関する処理を行います
    /// </summary>
    public class AccountController : Controller
    {
        /// <summary>
        /// アカウント新規作成画面を表示します
        /// </summary>
        /// <returns></returns>
        public ActionResult Create()
        {
            return this.View();
        }
 
        /// <summary>
        /// アカウント新規作成処理を実行します
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost()]
        [ValidateAntiForgeryToken()]
        public ActionResult Create(AccountModel model)
        {
            // ...登録しようとしているアカウント情報が登録可能かどうか判定する処理...
 
            // ...DBへ登録等の処理...
 
            // 登録完了画面を表示
            return this.View("Complete");
        }
 
        /// <summary>
        /// 処理完了画面を表示します
        /// </summary>
        /// <returns></returns>
        public ActionResult Complete()
        {
            return this.View();
        }
    }
}

AccountController.cs では CSRF対策 用 のトークンを検証する仕組みを実装します。 具体的には 26行目にある [ValidateAntiForgeryToken()] を記載することで、トークンが正しいものかどうかが検証されます。 正しいトークンが含まれていなければ、不正な処理として例外を発生させます。 例外処理がされてなければ、500 Internal Server Error としてレスポンスが返ってきます。

AccountController.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace WebApplication.Models
{
    public class AccountModel
    {
        /// <summary>
        /// アカウントIDを取得または設定します。
        /// </summary>
        public string Id { get; set; }
 
        /// <summary>
        /// アカウントパスワード取得または設定します。
        /// </summary>
        public string Password { get; set; }
    }
}

今回はシンプルに Id と パスワード のみ登録するようなモデルを実装しています。

Create.cshtml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@model WebApplication.Models.AccountModel
 
@{
    ViewBag.Title = "Create Account";
}
 
<h2>Create Account</h2>
 
@using (Html.BeginForm("Create", "Account", FormMethod.Post, new { @class = "form-horizontal" }))
{
    @Html.AntiForgeryToken()
 
    <div class="form-group">
        <label for="id" class="col-sm-2 control-label">ID</label>
        <span>@Html.TextBoxFor(m => m.Id, new { @class = "form-control" })</span>
    </div>   
    <div class="form-group">
        <label for="password" class="col-sm-2 control-label">Password</label>
        <span>@Html.PasswordFor(m => m.Password, new { @class = "form-control" })</span>
    </div>
    <div class="form-group">
        <span class="col-sm-offset-2"><input type="submit" class="btn btn-default" value="登録" /></span>
    </div>
}

Create.chstml では CSRF対策用の トークン を埋め込みます。 具体的には 11行目 にある @Html.AntiForgeryToken() を記載することで、トークンを埋め込むことができます。

Create.cshtml

1
2
3
4
5
@{
    ViewBag.Title = "Complete";
}
 
<h2>Complete</h2>

結果表示だけなので、特に何も実装はありません。。

CSRF対策 ができているか テスト

正常な経路のテスト

まずは正常な経路で動作することを確認します。

  1. /Account/Create へアクセスし、入力欄を埋めて、「登録」ボタンを押下します

  2. /Account/Complete へ遷移します

不正な経路のテスト

次に画面を介さず、いきなりアカウント作成を実行するような経路(不正な経路)をテストします。 具体的には Fiddler を利用して、直接アカウント作成するような経路をテストしてみます。

  1. Fidler の Composer タブ で遷移先のURLである POST: /Account/Create を入力します

  2. 「Execute」ボタンを押下します

  3. レスポンスをみると、エラーが返ってきていることが確認できます

参考記事

最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!