しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET のセキュリティ対策について考える

XSS や CSRF の話題は相変わらず結構多いですね。例えば、はまちや2さんのブログに最近書かれたエントリとか。

CSRFで強制ログインさせるというアイデア - ぼくはまちちゃん!(Hatena)

曰く、Hatena や Facebook など多くのサービスがログイン画面では CSRF 対策されていないとか。実際に書かれているようなことが起きたら怖いですねー。

で、本題なんですが、ASP.NET を使ったサービスでは XSS や CSRF に関してはあまり被害を聞かないなーと思いました。ぶっちゃけ、採用サイトが少なすぎるのが理由な気もするんですが、SQL インジェクションはよく聞きますが、XSS・CSRF は自分は特に被害を知りません。

XSS

XSS は悪意のある入力内容が、適切にエスケープされずに出力された場合に発生します。ということでエスケープをしましょう。

そもそも ASP.NET には HTML タグっぽいものが送信された時には「危険なタグが〜」というエラーになるので、XSS には比較的耐性があるかと思います。

Web Forms

<%-- ASP.NET 4 以前 --%>
<%= HttpUtility.HtmlEncode(Model.Name) %>
<%-- ASP.NET 4 以降 --%>
<%: Model.Name %>

Web Forms では ASP.NET 4 から <%: %> コードナゲットが追加され、デフォルトでエスケープされるようになりました。ASP.NET 4 より前では手動でエスケープする必要があります。

MVC

@* Razor を使用 *@
@Model.Name
@* エスケープされたくない場合 *@
@Html.Raw(Model.Name)

Razor はデフォルトでエスケープされるので、何も考えずにそのまま書けます。エスケープされたくない場合は Html.Raw ヘルパーを使います。

Web Pages

@* Razor を使用 *@
@Model.Name

Web Pages も Razor なので MVC とまったく同じです。

CSRF

不正なフォームから POST された時には処理を行ってはダメですよ。ワンタイムトークンを発行して、正規のリクエストか判別する方法が一般的かと。

Web Forms

protected override OnInit(EventArgs e)
{
    base.OnInit(e); 
    ViewStateUserKey = Session.SessionID;
}

ASP.NET の組み込み機能を活用し、Web 攻撃を回避する

Web Forms ではビューステートを持ってるので、そこにユニークな値をセットすることで対策を行えます。MS 的にはセッション ID を勧めているようです。

MVC

@using (Html.BeginForm())
{
    @* トークンを埋め込む *@
    @Html.AntiForgeryToken()
}
// トークンを検証する
[ValidateAntiForgeryToken]
public ActionResult Create()
{
    return View();
}

HTML 側で Html.AntiForgeryToken ヘルパーを呼び出すとクッキーと hidden 値にトークンが書き込まれます。そして POST 先のアクションに ValidateAntiForgeryToken 属性を付けておくと、自動的にトークンの検証が行われます。

MVC ではこれだけで CSRF 対策が出来るので、実装しておくことをお勧めします。

Web Pages

<form action="" method="post">
    @* トークンを埋め込む *@
    @AntiForgery.GetHtml()
</form>
if (IsPost)
{
    // トークンを検証
    AntiForgery.Validate();
}

AntiForgery ヘルパーが用意されているので、MVC までとはいきませんが、かなり簡単に対策出来ます。仕組みは MVC と同じというか MVC は AntiForgery ヘルパーを使って属性を実装しています。

ちなみにトークンの検証に失敗したときには例外が投げられます。

SQL インジェクション

LINQ to SQL や Entity Framework で LINQ を使いましょう。以上!!