ASP.NET MVCのXSS対策 ~クライアントサイドでの防止方法~
前項では、XSS対策のフレームワーク側の設定について解説しました。次にビュー側に悪意を持ったスクリプトが渡されてしまった場合を考えてみます。シナリオの大前提として、コントローラクラス全体にValidateInput属性が宣言されている場合です。
サンプルでは予定動作として、テキストを入力後、表示ボタンを押すと同一ページの下部に文字列が表示されるページになっています。
しかし実際にはスクリプトが混入されてもそのままスクリプトが実行されてしまうサイトだとします(図2~3)。サンプルではアラートダイアログを表示するスクリプトを利用します。
大まかな流れとして次のとおりです。
- ビュー側のテキストボックスからスクリプトを注入
- コントローラ側でメッセージをビュー側に渡す
- ビュー側でスクリプトが実行される
それでは上記の現象が発生してしまうページのソースの確認をしてみましょう。コントローラ側の設定は次のとおりです。
[ValidateInput(false)] [AcceptVerbs(HttpVerbs.Post)] public ActionResult Index(string message) { ViewData["Msg"] = message; return View(); }
今回は特にデータチェックなどは行っていません。危険なデータが入っている可能性があるメッセージをそのままビューに返します。
続いてViewPage側の設定は次のとおりです。
<h2><%= Html.Encode(ViewData["Message"]) %></h2> <form method="post" action="/Home/Index"> <h2><label for="message">メッセージを入力してください:</label></h2> <br /> <textarea name="message" cols="50" rows="3"></textarea> <br /> <%= ViewData["Msg"]%> <br /><br /> <input type="submit" value="送信!" /> </form>
コントローラから渡された値をダイレクトに表示するように記述しています。
つまり、スクリプトがコントローラから渡されてきても、そのまま実行できる状態となっています(図3)。
本来はコントローラ側ですべて危険なスクリプトなどを検証できればいいのですが漏れる可能性があります。そんな時のために、コントローラ側から渡される値は第2回で紹介した、Html.Encodeメソッドを活用します(図4)。
<h2><%= Html.Encode(ViewData["Message"]) %></h2> <form method="post" action="/Home/Index"> <h2><label for="message">メッセージを入力してください:</label></h2> <br /> <textarea name="message" cols="50" rows="3"></textarea> <br /> <%= Html.Encode(ViewData["Msg"])%> <br /><br /> <input type="submit" value="送信!" /> </form>
Html.Encodeメソッドはパラメタとして渡された値をすべてエンコードするメソッドです。そのためパラメタとしてHtml文字列などが入っていても、すべてエンコードして出力されます。コントローラ自身がスクリプトの受け入れを許容していても、各アクションメソッドまで許容しているとは限りません。そんな時はHtml.Encodeメソッドを活用して値をエンコードしましょう。
ASP.NET MVCのCSRF対策
クロスサイト リクエスト フォージェリ(CSRF)と言えば4年経った今でも、はまちちゃんが某SNSにて世に知らしめた脆弱性のことと言った方が分かる方が多いのではないでしょうか? Webページ上でスクリプトやHTTPリクエストやリダイレクトを使って、ユーザーが意図していない操作を実行してしまう攻撃手法です。認証が必要なサイトであれば、ユーザーが持つ権限を利用することで削除や編集などを行うことができます。
このCSRF対策はコストは低くとも、ある程度の効果は見込めるので、ぜひ実装してください。設定方法は以下の2点を実行するだけです。
- ViewPage側にHtml.AntiForgeryTokenメソッドを記述する(トークンの生成)
- Controllre側でValidateAntiForgeryToken属性を設定する(トークンチェック)
AntiForgeryTokenメソッドは、hiddenフィールドとCookieにトークンを生成しValidateAntiForgeryToken属性を設定することで、リクエストを送ってきたユーザーがビューを表示させたユーザーと同一か、悪意を持った攻撃者でないかをトークンを利用してチェックしています(図5)。
トークンに対して何か処理を行うわけではないので、ソースは記述するだけです。
<h2>CSRF</h2> <form method="post" action="/Home/CSRF"> <h2><label for="message">メッセージを入力してください(トークンチェック):</label></h2> <br /> <textarea name="message" cols="50" rows="3"></textarea> <br /> <%= Html.Encode(ViewData["Msg"])%> <br /><br /> <%= Html.AntiForgeryToken() %> <input type="submit" value="送信!" /> </form>
XSSのサンプルを流用しています。submitボタンの前にHtml.AntiForgeryTokenメソッドを記述するだけです。
[ValidateAntiForgeryToken()] [AcceptVerbs(HttpVerbs.Post)] public ActionResult CSRF(string message) { ViewData["Msg"] = message; return View(); }
コントローラ側では、利用したいコントローラまたはアクションメソッド前にValidateAntiForgeryToken属性を記述するだけなので、非常にお手軽です。
この設定はAjaxリクエスト時にも同じ方法になりますので、積極的に使用しましょう。
ASP.NET MVCのSQLインジェクション対策
SQLインジェクションは、動的にクエリをくみ上げるWebサイト上に悪意あるSQLクエリを注入することで、データの改ざんや削除などを行う攻撃手法です。
ASP.NET MVCにおけるSQLインジェクション対策は、ASP.NET 3.5 SP1以降で動作するフレームワークである点が挙げられます。つまり、基本的にデータアクセステクノロジにLINQを活用するという点です。LINQはSelectクエリのみをサポートしているのでデータの改ざんが行われる訳ではありません。また、実行コードはコンパイルが完了しているため、クエリの改ざんなどが行われないという保証がされています。
なぜLINQがSQLインジェクション対策になるのか詳しく知りたい方は『LINQ to SQLが通常のSQLより優れた選択肢である理由』を参照してください。