情報応用演習Ⅰ(2024)

【T3b】POSTを処理する(5/5)

プロジェクトタイプASP.NET Core (空)
プロジェクト名T3b
ソリューション名PIT3
ターゲットフレームワーク.NET 8.0(長期的なサポート)
最上位レベルのステートメントを使用しない使用する(チェックオフ)
注意
  • 本ページの作業内容は 前のページまでの続き になっていることに注意せよ.
    • 先に前のページまでをすべて読み,指示されている作業を済ませてから本ページを読むこと.
    • プロジェクトの作成作業については準備作業を参照せよ.

3b-5. POSTリクエストとフォームについての注意点

今回のようなPOSTリクエストを受け付けるプログラムでは1つ注意するべきことがある. それはPOSTリクエストが,リスト3b-2-2のような こちらの用意したページのフォームによって作られるとは限らない , ということである.

現に,先ほどの手打ちによってPOSTリクエストは用意したフォームによって作られたものではないし, この方法を応用すると フォームの入力欄にはないデータを入力することすらできてしまう . このことを確かめてみよう.

Tera Term で「編集」→「画面のクリア」と「バッファのクリア」の両方をそれぞれクリックして画面を空にしてから, プロジェクトが実行中であることを確認してから,もう一度「ファイル」→「新しい接続」で表3a-4-1の ように入力して「OK」ボタンをクリックして接続を開始しよう. そして_に示すPOSTリクエストを実行を実行してみよう.緑字の部分は図3b-4-1との差分である.

実行するPOSTリクエスト3

正しく入力できた場合,_のように表示されるはずである.

手打ちリクエストの実行結果2

先ほどと同じく,HTML部分(_♠)をresponse3.htmlという名前でファイルに保存して開いてみよう(_). 前後のヘッダーや余計な文字列は削除すること.

response3.htmlの表示結果

ページ上の「フォームデータ(「キーと値」の組)」の部分を見ると,リスト3b-2-2のinput要素で入力欄を用意していたデータである foobarだけでなく,入力欄が存在しないはずのbazというデータが認識されていることが分かる. 今回のような入力を受け付けるリソース(今回の場合はHogeコントローラーのDumpPostアクション)は, 意図しないデータを入力されることを想定してその対策を行うべきである. この対策を行わないとウェブアプリに意図しない不正なデータを入力されて任意のコードを実行されてしまったり, クロスサイトリクエストフォージェリと呼ばれる攻撃に利用されてしまうことがある. 幸い,ASP.NET Core はこの対策のための機能を提供している.

ではその機能を試してみよう.このために 先ほどのような入力を受け付けるアクションメソッドに[ValidateAntiForgeryToken]属性 もしくは[AutoValidateAntiforgeryToken]属性を付加する .この属性を付加されたアクションメソッドは こちらの想定したページからのリクエスト以外は受け付けなくなる.

デバッグ実行を停止してから,Controllers/HogeController.cs のDumpPost()メソッドに_のように書き換えよう.

Controllers/HogeController.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
using Microsoft.AspNetCore.Mvc;

namespace T3b.Controllers
{
    public class HogeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult DumpPost()
        {
            // (表示用)Formデータの「キーと値」の組をViewDataに入れる
            foreach (var ent in Request.Form)
            {
                ViewData[ent.Key] = ent.Value;
            }

            return View();
        }
    }
}

書き換えたら実行してみよう.実行してウェブブラウザが起動したら /Hoge/Index にアクセスして, 開発ツールのネットワークモニターを表示した状態で入力欄に適当な値を入力して「送信」ボタンを押すと, __のように表示されるはずである.

実行結果

「ファイル」の列が DumpPost となっている項目を選択して,表示された画面の「応答ヘッダー」の横の「生ヘッダー」を オンにするとサーバーから400 Bad Requestが戻ってきていることが分かる(_). 先ほどの対策の効果であるが正規のフォームから発せられたリクエストが拒否されてしまっている. [ValidateAntiForgeryToken]属性や[AutoValidateAntiforgeryToken]属性を つけたアクションでは,フォームデータにアンチフォージェリトークンという隠しデータが含まれていないと,このように アクションの受付を400 Bad Requestで拒否するようになる. この隠しデータを送信データに含めるにはフォームの側にも手を加える必要がある.このためには以下のようにする.

デバッグ実行を停止して,フォームを設置しているビューである Views/Hoge/Index.cshtml を開いて, _のように変更しよう.

Views/Hoge/Index.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
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    Layout = null;
}

<!DOCTYPE html>

<html lang="ja">
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <h1>今見ているのは /Hoge/Index </h1>

    <form asp-controller="Hoge" asp-action="DumpPost" method="POST">
        入力値1: <input type="text" name="foo" /><br />
        入力値2: <input type="text" name="bar" /><br />
        <input type="submit" value="送信" />
    </form>

</body>

</html>

_の1行目はタグヘルパーと呼ばれる ASP.NET Core の機能を利用可能にするためのディレクティブである.これは複雑なHTMLの記述を助けるための機能である.

_の17行目では action 属性の代わりに, asp-controller 属性や asp-action 属性といったHTMLでは見慣れない 属性が表れている.これは前述したタグヘルパーの一種で, form 要素の action 属性の値を生成するためのものである. 当然のことながらこれらはHTMLの標準には含まれない ASP.NET Core の独自の属性であり,前処理で通常のHTMLの属性に置き換えられてからクライアント側に送られるため出力結果のHTMLには表れない.

asp-controller 属性と asp-action 属性は 「どのコントローラーの」「どのアクション」かを指定する ものであり, これらを使用することで,action 属性に適切な値が設定される.今回のウェブアプリの構成では コントローラー名/アクション名というURLでアクセスするように構成しているが, これらのタグヘルパーを使用することでURIのマッピングの設定に基づいて自動的に指定されたコントローラー&アクションのための URLを生成してくれる.ちなみにこの場合は asp-controller 属性は省略可能である.コントローラーの指定を 省略した場合は,そのビューが属しているコントローラーそのものが指定されたものとみなされる.

またこれらのタグヘルパーには,そのフォームに前述した アンチフォージェリトークンのための隠しデータを追加する という機能もある. form 要素の action 属性を手動設定せず,かつフォーム用のタグヘルパーを使用している場合は, フォーム内に type 属性に"hidden"を指定した input 要素が自動的に挿入され,それにアンチフォージェリトークンのための 隠しデータが埋め込まれる.

ここまで書けたら実行してみよう.実行してウェブブラウザが起動したら /Hoge/Index にアクセスしてみよう. ページを右クリックして「ページのソースを表示」をクリックすると,そのページの元となったHTMLが表示される(_). _に示す通り, .cshtml ファイル上では form 要素に asp-controller や asp-action といったタグヘルパーを指定していたが, これらは事前処理されて,代わりに action 属性が設定されており,その値としてこのアプリのURLルーティング定義に基づいた, コントローラー/アクションを指定するURLが設定されていることが分かるだろう.

また,フォーム内に__RequestVerificationTokenという名前の付いた input 要素が追加されていることが分かるだろう.

実行結果

これが前述したアンチフォージェリトークンである.この値は固定ではなくアクセスするたびに変化する. [ValidateAntiForgeryToken]属性や[AutoValidateAntiforgeryToken]属性をつけたアクションは, フォームデータにこのアンチフォージェリトークンが含まれているかどうかを検証するようになり, それが含まれていない限りフォームの処理を拒否するようになる. (とは言っても,正規にフォームが置いてあるページを取得してから,アンチフォージェリトークンを含めた 任意データをPOSTすることももちろん可能なのでこの方法は不正なデータ入力に対する絶対の防壁ではない ということは理解しておこう).

それでは実際に送信がうまくいくことを確認しよう.開発ツールのネットワークモニターを表示した状態で 入力欄に適当な値を入力して「送信」ボタンを押す.すると__のように表示されるはずである.

実行結果

「ファイル」の列が DumpPost となっている項目を選択して,表示された画面の「応答ヘッダー」の横の「生ヘッダー」を オンにすると,今度は先ほどと異なりサーバーから200 OKが戻ってきていることが分かる(_). ページ上の「フォームデータ(「キーと値」の組)」の部分を見ると,アンチフォージェリトークンのための __RequestVerificationTokenというデータが含まれていることが分かるだろう. これでフォームのページを経ない POST リクエストを防ぐことができるようになった. 最後に Tera Term を用いて手打ちで POST リクエストを行ってもサーバー側から拒否されることを確認しておこう

Tera Term を起動していなければ起動して設定ファイル RAW_HTTP.ini を読み込もう.先ほどから起動させたままで あれば「編集」→「画面バッファのクリア」をクリックして画面を空にしておこう. プロジェクトが実行中であることを確認してから ,「ファイル」→「新しい接続」で表3a-4-1のように入力しよう. ただし「TCPポート#」はプロジェクトごとに異なることに注意しよう. 「ホスト」「サービス」「TCPポート#」の3項目を正しく入力したら「OK」ボタンをクリックして接続を開始して,先ほど実行したのと同じ_のテキストメッセージを打ち込もう. 記号種や大文字小文字,空白や改行の個数なども厳密に同じである必要がある

正しく入力できた場合,_のように表示されるはずである. Firefox のネットワークモニターで確認したときと同じく,400 Bad Requestが返されてきていることが分かる.

手打ちリクエストの実行結果3
提出時の注意

今回の演習で作成する三個のHTMLファイル,response1~3.html は 作業成果物の一部として提出する必要がある . 提出時は今回作成したソリューション PIT3 のソリューションフォルダ(PIT3.slnがあるのと同じフォルダ; _ )に これらのファイルを置いてから,提出用のZIPファイルを作成すること.

response1~3.htmlの置き場所

ここまでを確認できたら今回のチュートリアルは完了である. なお今回は課題が出題されている.忘れずに取り組むこと

Last updated on 2024-05-10
Published on 2024-05-10

Powered by Hugo. Theme by TechDoc. Designed by Thingsym.