カテゴリ: C# 更新日: 2026/07/04

C#のASP.NETでWebサイトを守る!初心者でもできるデフォルトセキュリティ機能の使い方完全ガイド

C#のASP.NETでデフォルトのセキュリティ機能を活かす方法
C#のASP.NETでデフォルトのセキュリティ機能を活かす方法

先生と生徒の会話形式で理解しよう

生徒

「C#を使ってWebサイトやWebアプリケーションを作ってみたいのですが、ハッカーからの攻撃やセキュリティ対策が難しそうで不安です。」

先生

「安心してください。C#でWebアプリを作るための仕組みであるASP.NETには、最初から強力なセキュリティ機能が標準装備されています。自分で複雑なプログラムを組まなくても、デフォルトの機能を有効にするだけで多くの危険からサイトを守ることができますよ。」

生徒

「初心者でも初期設定のままで安全性を高められるんですね!具体的にはどのように使うのか、設定方法や仕組みを教えてください。」

先生

「それでは、プログラミング初心者の方にも分かりやすく、基本的な使い方と設定の手順を丁寧に見ていきましょう!」

1. ASP.NETのセキュリティと初期機能とは?

1. ASP.NETのセキュリティと初期機能とは?
1. ASP.NETのセキュリティと初期機能とは?

C#でWebサイトやシステムを開発するとき、多くの開発者がASP.NET(エーエスピー・ドットネット)というフレームワークを使用します。フレームワークとは、Webアプリを効率よく作るための「土台」や「部品集」のようなものです。パソコンを触ったことがない方でも、スマートフォンアプリやネットショッピングのサイトを想像すると分かりやすいでしょう。誰でも利用できる便利なサイトの裏側では、悪意のあるユーザーによる不正な操作を防ぐ防犯対策が必須となります。

ASP.NETには、この防犯対策が「最初から標準で」組み込まれています。これをデフォルトのセキュリティ機能と呼びます。鍵付きの頑丈な家を最初から建ててくれるような状態をイメージしてください。開発者は特別な防犯装置をゼロから自作する必要がなく、デフォルトの機能を正しく有効化して活かすだけで、安全で信頼性の高いシステムを構築できるようになっています。まずは、この初期機能をしっかりと有効に保つことが、Webセキュリティの第一歩です。

2. 画面への悪意ある入力を防ぐHTMLエンコードの仕組み

2. 画面への悪意ある入力を防ぐHTMLエンコードの仕組み
2. 画面への悪意ある入力を防ぐHTMLエンコードの仕組み

Webサイトのトラブルで多いのが、お問い合わせフォームや検索ボックスなどの文字を入力する場所に、不正なプログラムのコードを書き込まれてしまう現象です。これをクロスサイトスクリプティング(XSS)と呼びます。もし対策をしていないと、掲示板の書き込み欄に悪質なプログラムが埋め込まれ、それを開いた他のユーザーのパソコンで勝手に怪しい画面が立ち上がるといった被害が発生します。学校の黒板に、見た人を騙す偽の命令文を勝手に書かれてしまうような状態です。

ASP.NETでは、標準の画面表示の仕組みである「Razor(レイザー)ビュー」を使うだけで、この問題を自動的に防ぐことができます。画面に文字を出力する際に、プログラムの命令として意味を持つ特殊な文字を、単なる「普通の文字列」として表示するように安全に変換してくれます。この変換処理をHTMLエンコードと言います。例えば、プログラムを実行する合図となる記号を、安全な別の文字列に自動で置き換えて画面に描画します。これにより、悪意あるコードが書き込まれても、ただの文字として表示されるだけで無害化されます。

以下は、コントローラーと呼ばれる処理担当の部分から、画面へ文字を渡すシンプルなC#の記述例です。特別な対策コードを自分で書かなくても、標準の仕組みが安全性を確保します。


using Microsoft.AspNetCore.Mvc;

namespace WebApp.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            // ユーザーが入力したと想定される危険な文字列
            string userInput = "<script>alert('攻撃')</script>";
            
            // 安全に画面へデータを渡すためにバッグに詰める
            ViewBag.Message = userInput;
            
            return View();
        }
    }
}

このデータを表示する画面側のHTMLファイル(cshtmlファイル)では、以下のように記述するだけで自動的に安全な変換が行われます。


<div class="container mt-4">
    <h3>ユーザーからのメッセージ</h3>
    <p class="border p-2">@ViewBag.Message</p>
</div>

通常の画面表示の結果は以下のようになり、プログラムは起動せず、文字として安全に出力されます。


<script>alert('攻撃')</script>

3. なりすまし送信を撃退するCSRF対策トークンの設定方法

3. なりすまし送信を撃退するCSRF対策トークンの設定方法
3. なりすまし送信を撃退するCSRF対策トークンの設定方法

次に警戒すべきなのが、CSRF(シーエスアールエフ)という攻撃です。これは日本語で「クロスサイトリクエストフォージェリ」と言い、日本語に直すと「偽物の要求をサイト間で送りつけること」です。ユーザーがネットショッピングにログインしている状態のまま、別の悪質な罠サイトを開いてしまったときに発生します。罠サイトに仕込まれたボタンをうっかり押すと、ログイン中のショッピングサイトに対して「高級な商品を注文する」という命令が、本人の気付かない裏側で勝手に送信されてしまうのです。銀行のハンコを持ったまま席を外した隙に、他人が勝手に書類にハンコを押して提出するような被害です。

ASP.NETでは、この「なりすまし」の命令を見破るために、反偽造トークン(Antiforgery Token)という秘密の合言葉をデフォルトで発行する機能があります。画面を表示したときにサーバーが一度限りの使い捨ての合言葉を作成し、画面のボタンとサーバー側の両方でその合言葉を共有します。データを受け取ったサーバーは、合言葉が一致しているかどうかを厳しくチェックします。罠サイトから送られた命令にはこの正しい合言葉が含まれていないため、サーバーは即座に「怪しい命令」として処理を拒否します。

この機能を有効にするには、データを送信するサーバー側の処理(アクションメソッド)に、専用の目印を付けるだけです。C#ではこれを属性(Attribute)と呼び、角括弧の中に名前を書いて指定します。以下がその記述方法です。


using Microsoft.AspNetCore.Mvc;

namespace WebApp.Controllers
{
    public class OrderController : Controller
    {
        // データを送信するための画面を表示する
        [HttpGet]
        public IActionResult Create()
        {
            return View();
        }

        // 送信されたデータを受け取る処理に、偽造防止チェックの目印を付ける
        [HttpPost]
        validateAntiForgeryToken
        public IActionResult Create(string itemName, int quantity)
        {
            // 合言葉が正しい場合のみ、ここの注文処理が実行されます
            return Content("注文を正常に受け付けました。");
        }
    }
}

画面側のフォームを作るHTMLでは、ASP.NETの標準機能を使うことで、自動的に隠し要素として秘密の合言葉が埋め込まれます。開発者が手動で合言葉の文字列を生成する必要はありません。


<form asp-controller="Order" asp-action="Create" method="post">
    <div class="mb-3">
        <label class="form-label">商品名</label>
        <input type="text" name="itemName" class="form-control" />
    </div>
    <div class="mb-3">
        <label class="form-label">数量</label>
        <input type="number" name="quantity" class="form-control" />
    </div>
    <button type="submit" class="btn btn-primary">注文する</button>
</form>

正しく送信された場合の実行結果画面には、以下のようなメッセージが安全に表示されます。


注文を正常に受け付けました。

4. データベースを不正操作から守るパラメータ化クエリの重要性

4. データベースを不正操作から守るパラメータ化クエリの重要性
4. データベースを不正操作から守るパラメータ化クエリの重要性

多くのWebアプリケーションでは、ユーザーの名前やパスワード、商品の情報などを保存するためにデータベースという電子的な整理棚を使用しています。この整理棚からデータを探したり保存したりするときは、専用の命令文を使います。この命令文の隙を突いて、データベースを破壊したり、他人の個人情報を盗み出したりする重大な攻撃をSQLインジェクションと呼びます。検索ボックスに「すべてのデータを消去せよ」という裏の命令を紛れ込ませて入力し、システムを誤作動させる手口です。役所の受付で「名前」を書く欄に「金庫の鍵を開けろ」と書いて、受付の人を騙すような行為です。

C#のASP.NETでは、データベースとの通信に標準で使われる「Entity Framework Core(エンティティ・フレームワーク・コア)」という仕組みを利用することで、この危険性を根絶できます。Entity Framework Coreでは、ユーザーが入力した文字を命令文としてそのまま結合せず、必ず「純粋なデータ(値)」として分けて処理するパラメータ化クエリという方式をデフォルトで採用しています。これにより、入力欄にどれだけ巧妙な命令文が書き込まれても、データベース側はそれを単なる「名前というデータ」として扱うため、誤作動を起こすことがありません。

以下は、Entity Framework Coreを使用して、安全にデータベースからユーザー情報を検索するC#のプログラム例です。初心者でも簡単に安全なコードが書けます。


using System.Linq;
using Microsoft.AspNetCore.Mvc;

namespace WebApp.Controllers
{
    public class AccountController : Controller
    {
        private readonly MyDbContext _context;

        public AccountController(MyDbContext context)
        {
            _context = context;
        }

        public IActionResult Search(string searchName)
        {
            // ユーザー入力を直接命令文に混ぜず、自動で安全なデータとして扱います
            var userList = _context.Users
                                   .Where(u => u.Name == searchName)
                                   .ToList();

            return View(userList);
        }
    }
}

このプログラムが動いたとき、裏側ではデータベースに対して以下のような安全な形式で問い合わせが実行されます。直接文字が合体しないため安心です。


SELECT * FROM Users WHERE Name = @searchName

5. 通信の盗聴を遮断するHTTPS強制化の設定

5. 通信の盗聴を遮断するHTTPS強制化の設定
5. 通信の盗聴を遮断するHTTPS強制化の設定

インターネット上でデータをやり取りするとき、暗号化されていない普通の通り道を使っていると、途中で悪意のある第三者に通信内容を覗き見されてしまうリスクがあります。特に、街中の無料Wi-Fiなどを利用しているときは注意が必要です。パスワードやクレジットカード番号がそのままの状態で空気中を飛び交うようなもので、これを盗聴と呼びます。この通信を丸ごと暗号化し、中身を見られないようにする仕組みがHTTPS(エイチティーティーピーエス)です。手紙を透明な封筒ではなく、頑丈な鍵付きの箱に入れて相手に届けるイメージです。

ASP.NETで作られたWebアプリは、最初からこのHTTPSによる安全な通信を強制する仕組みが組み込まれています。もしユーザーが間違えて暗号化されていない昔の接続方法でアクセスしてきても、自動的に安全なHTTPSのURLへと転送(リダイレクト)してくれます。この設定は、プログラムの起動時のルールを書き込む「Program.cs」というファイルで、デフォルトで1行記述されているだけで有効になります。開発を始めるときに元から用意されている設定なので、消さずにそのまま残しておくことが重要です。

以下は、Webアプリ全体にセキュリティのルールを適用する「Program.cs」のファイル内での該当部分の記述例です。


var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// 開発環境だけでなく、本番環境でもHTTPSを強制するためのデフォルトの処理
if (!app.Environment.IsDevelopment())
{
    app.UseHsts(); // より厳格なセキュリティ設定をブラウザに指示する命令
}

// 自動で安全な通信のURLへ転送する機能を有効化します
app.UseHttpsRedirection();

app.UseStaticFiles();
app.UseRouting();
app.MapDefaultControllerRoute();

app.Run();

この設定が生きているお陰で、ユーザーがサイトに訪れた際の接続状況は常に以下のように安全な状態へ切り替わります。


通常の接続要求(http://example.com)を検知しました。
安全な接続先(https://example.com)へ自動的に案内を変更します。

6. 大切なパスワードを安全に保管するハッシュ化の基本

6. 大切なパスワードを安全に保管するハッシュ化の基本
6. 大切なパスワードを安全に保管するハッシュ化の基本

Webアプリに会員登録の機能を作る場合、ユーザーが設定したパスワードをそのままの文字でデータベースに保存してはいけません。万が一、何らかの理由で整理棚のデータが外部に漏洩してしまった場合、すべてのユーザーのパスワードが丸見えになってしまい、他のサイトでも不正ログインされる二次被害につながるからです。そのため、パスワードは必ず元に戻せない複雑な文字列へと変換して保存する必要があります。この変換技術を暗号学的ハッシュ化と呼びます。果物をジューサーにかけて完全にドロドロのジュースにしてしまい、元の果物の形が絶対に分からないようにする加工方法です。

ASP.NETには、このハッシュ化を極めて高度なセキュリティレベルで簡単に行える「PasswordHasher(パスワードハッシャー)」という便利な道具がデフォルトで提供されています。これを使うと、たとえ同じ「password123」という文字を入力しても、毎回異なる複雑な暗号のような文字列に変換され、データベースにはその変換後の文字列だけが保存されます。ログイン時には、入力されたパスワードを再度同じ方法でジュース状にして、保存されているデータと一致するかどうかだけを安全に照合します。

以下は、ユーザー登録の際にパスワードを安全にハッシュ化して処理するC#のプログラムコードの例です。


using Microsoft.AspNetCore.Identity;

namespace WebApp.Services
{
    public class AccountService
    {
        public string RegisterUser(string rawPassword)
        {
            // パスワードを安全に加工するための道具を呼び出す
            var hasher = new PasswordHasher<object>();
            
            // 元の文字を、予測不可能な複雑な文字列に変換します
            string hashedPassword = hasher.HashPassword(null, rawPassword);
            
            // この変換された文字列をデータベースに保存します
            return hashedPassword;
        }
    }
}

このプログラムを通過したパスワードは、元の文字の長さに関わらず、以下のような一見すると意味不明な文字列の並びに変換されて出力されます。


AQAAAAEAACcQAAAAEHz9bXYZ789qwert...(解読不可能な文字列)

7. クッキーの漏洩を防ぐ安全な設定と管理

7. クッキーの漏洩を防ぐ安全な設定と管理
7. クッキーの漏洩を防ぐ安全な設定と管理

Webサイトにログインした後、別のページに移動してもログイン状態が維持されているのは、ブラウザにクッキー(Cookie)という小さな引換券が保存されているからです。この引換券は、サーバーが「あなたはログイン済みの会員さんですね」と見分けるための重要な証明書です。もしこの引換券が、悪いプログラムによって盗まれたり、暗号化されていない通信から漏れてしまったりすると、他人がその引換券を使って勝手に本人としてログインできてしまいます。これをセッション乗っ取りと言います。ホテルの部屋のカードキーを廊下に落として、他人に拾われてしまうような危険性です。

ASP.NETでは、このクッキーという引換券を厳重に保護する設定が最初から有効になっています。主に2つの防犯キーが自動的に設定されます。1つは、JavaScriptなどの画面側のプログラムからクッキーの中身を絶対に覗けないようにロックする「HttpOnly(エッチティーティーピーオンリー)」という属性です。もう1つは、暗号化されたHTTPS通信のときだけしかクッキーを送受信しないように制限する「Secure(セキュア)」属性です。これにより、引換券の盗難リスクを大幅に減らすことができます。

以下は、独自のクッキーを発行して設定する際、デフォルトの安全な設定値を明示的に適用するC#の記述例です。


using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace WebApp.Controllers
{
    public class CookieController : Controller
    {
        public IActionResult SetSecureCookie()
        {
            // クッキーの取り扱いルールを厳しく設定するためのオプション
            CookieOptions options = new CookieOptions
            {
                // プログラムからの覗き見を禁止する
                HttpOnly = true,
                // HTTPS通信のときだけ送信する
                Secure = true,
                // 同じサイト内でのみ利用を制限し、外部からの不正利用を防ぐ
                SameSite = SameSiteMode.Strict,
                Expires = DateTimeOffset.UtcNow.AddDays(1)
            };

            // 安全な設定を付けたクッキーをブラウザに保存させます
            Response.Cookies.Append("UserSessionToken", "SecretValue123", options);

            return Content("安全な設定でクッキーを保存しました。");
        }
    }
}

この処理が実行されると、ブラウザの管理領域には以下のように最高水準の防犯属性が追加された状態でデータが格納されます。


クッキー名: UserSessionToken
安全属性: HttpOnly=有効, Secure=有効, SameSite=Strict

8. システムの内部情報を隠すエラー画面の切り替え

8. システムの内部情報を隠すエラー画面の切り替え
8. システムの内部情報を隠すエラー画面の切り替え

プログラミングをしてアプリを作っていると、様々な原因でエラーが発生します。開発している最中は、どこが間違っているのかを突き止めるために、エラーが起きた場所や原因が詳しく書かれた詳細な画面が表示されると非常に便利です。しかし、この詳細なエラー画面をそのままインターネット上に公開してはいけません。詳細なエラー画面には、システムの構造、プログラムのファイル名、データベースのテーブル名など、ハッカーにとって「攻撃のヒント」となる重要な情報がたくさん含まれているからです。家の設計図や、金庫のメーカー名を泥棒に見せてしまうようなものです。

ASP.NETでは、アプリが動いている環境が「開発中(Development)」なのか「本番公開中(Production)」なのかを自動で判断し、表示するエラー画面を完全に切り替える機能がデフォルトで備わっています。本番環境では、詳細なエラー情報をすべて隠し、一般のユーザー向けに「エラーが発生しました。時間をおいてやり直してください」というような、簡潔で安全な専用の画面だけを見せるように設定されます。これにより、内部の構造を探られるリスクを未然に防ぎます。

この切り替えの仕組みも、先ほどの「Program.cs」の中でスマートにコントロールされています。C#での条件分岐の機能を使って、以下のように記述されています。


using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// 現在のアプリの実行環境を厳しくチェックします
if (app.Environment.IsDevelopment())
{
    // 開発中の場合は、原因究明のために詳細なエラー画面を表示します
    app.UseDeveloperExceptionPage();
}
else
{
    // 一般公開の本番環境の場合は、安全なエラー案内用のページへ転送します
    app.UseExceptionHandler("/Home/Error");
}

app.MapDefaultControllerRoute();
app.Run();

本番公開中の環境で不測のエラーが起きた場合、外部の人間が見ることになる実際の出力結果は、以下のように中身が保護されたシンプルなものになります。


申し訳ありません。リクエストの処理中にエラーが発生しました。
エラーコード: 500(内部の詳細は非公開です)
カテゴリの一覧へ
新着記事
New1
COBOL
COBOLのデバッグ方法を徹底解説!初心者向けDISPLAY活用ガイド
New2
C#
C#のLINQでグループ化と集計!GroupByとCountを初心者向けに解説
New3
C#
C#のシングルトンパターン実装方法と注意点を徹底解説!初心者向け完全ガイド
New4
Azure
Azure WAFの誤検知を解消!除外リスト設定とチューニング方法を初心者向けに徹底解説
人気記事
No.1
Java&Spring記事人気No1
C#
C#の文字列を数値に変換する方法(int.Parse・TryParse)をわかりやすく解説!
No.2
Java&Spring記事人気No2
COBOL
COBOLの数値データ型「PIC 9」の使い方と注意点をやさしく解説!
No.3
Java&Spring記事人気No3
C#
C#のbool型を完全解説!初心者でもわかるtrueとfalseの基本と使い方
No.4
Java&Spring記事人気No4
C#
C#のトランザクション処理を完全ガイド!初心者でもわかるCommit・Rollbackの使い方
No.5
Java&Spring記事人気No5
C#
C#のラムダ式の書き方と構文を初心者向けに完全解説
No.6
Java&Spring記事人気No6
C#
C#のLINQでOrderByを使った並び替えを完全ガイド!初心者でもわかるソート方法
No.7
Java&Spring記事人気No7
Azure
Azureストレージの冗長性比較!LRS/GRS/ZRSの選び方とコストの最適解を完全解説
No.8
Java&Spring記事人気No8
COBOL
COBOLのコンパイラと開発環境を徹底解説!初心者にもわかりやすい入門ガイド