セキュリティ対策まとめ(XSS / CSRF / SQLインジェクション)— ASP.NET Core MVC 実務の基本
Webアプリケーションの脆弱性は、多くの場合 「信頼できない入力値」 を適切に処理しないことから生まれます。
ASP.NET Core MVC で強固な基盤を作るには、フレームワークが提供する保護機能を 「なぜ」「どのように」使うか を理解することが不可欠です。
この記事では、実務でまず押さえるべき 3 大対策を コード付きで整理します。
- XSS(クロスサイトスクリプティング)
- CSRF(クロスサイトリクエストフォージェリ)
- SQLインジェクション
1. XSS(クロスサイトスクリプティング)防止
XSS とは
攻撃者が悪意あるスクリプトをページに埋め込み、閲覧者のブラウザ上で実行させる攻撃です。
基本原則は 「入力の検証」 と 「出力のエンコーディング」 です。
ASP.NET Core MVC がデフォルトで守ってくれること
Razor は デフォルトで HTML エンコードします。
たとえば @Model.Comment に <script>alert('xss')</script> が入っていても、Razor は <script>... のように変換して出力するため、ブラウザはスクリプトとして実行しません。
やってはいけない(危険): Html.Raw() の乱用
Html.Raw() は Razor の自動エスケープを無効化します。
ユーザー入力に対しては絶対に不用意に使わないでください。
@* 危険:ユーザー入力をそのまま HTML としてレンダリング *@
@Html.Raw(Model.UserInput)
@* 安全:Razor が自動で HTML エンコード *@
<p>@Model.UserInput</p>
実務でのコツ
- 表示する文字列は **「基本はエスケープされる」**前提で設計する
- どうしても HTML を許可する場合は、許可タグのホワイトリスト方式を検討する(無制限な Raw はNG)
2. CSRF(クロスサイトリクエストフォージェリ)防止
CSRF とは
ログイン済みユーザーのセッション(Cookie)を悪用し、ユーザーの意図しない操作(例:パスワード変更、決済)を 別サイトから勝手に実行させる攻撃です。
ASP.NET Core MVC の基本対策:Antiforgery トークン
フォーム送信に 一意のトークンを含め、サーバー側で検証します。
これにより「正当な画面(自サイト)から送られたPOSTか?」を確認できます。
View 側(フォーム)
<form asp-controller="Account" asp-action="UpdateProfile" method="post">
@Html.AntiForgeryToken()
<input type="text" name="Username" />
<button type="submit">保存</button>
</form>
Controller 側(検証)
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult UpdateProfile(UserViewModel model)
{
// トークンが一致しない場合、ここは実行されず 400 などで弾かれる
return View();
}
実務でのコツ
- フォームPOSTには基本
@Html.AntiForgeryToken()+[ValidateAntiForgeryToken] - API(JSON)でやる場合は構成が変わる(Cookie 認証 + SPA の場合はヘッダー連携など)
※MVC + Razor のフォーム中心なら上の組み合わせをまず徹底でOK
3. SQLインジェクション防止
SQLインジェクションとは
SQL のパラメータ部分に悪意ある SQL を注入し、DB を不正操作する攻撃です。
EF Core(LINQ)なら基本安全
EF Core の LINQ クエリは内部的に パラメータ化クエリを生成します。
ユーザー入力がそのまま SQL として解釈されにくいのが大きな利点です。
// 安全:EF Core が自動的にパラメータ化する
var user = _context.Users.FirstOrDefault(u => u.Email == inputEmail);
やってはいけない(危険): 文字列連結で生SQLを作る
// 危険:SQLインジェクションの脆弱性がある
var query = "SELECT * FROM Users WHERE Email = '" + inputEmail + "'";
_context.Users.FromSqlRaw(query);
正しい(安全): パラメータ化する
// 安全:パラメータ化する
var query = "SELECT * FROM Users WHERE Email = {0}";
var users = _context.Users.FromSqlRaw(query, inputEmail).ToList();
生SQLが必要なケースはありますが、文字列連結は禁止と覚えておくと事故が減ります。
4. セキュリティ対策が効く流れ(リクエスト・ライフサイクル)
以下は「フォームPOSTを例にした」ざっくりした流れです。
5. 堅牢なフォーム設計(バリデーションは最後の砦)
脆弱性を防ぐ上で「最後の砦」になるのが 入力バリデーションです。
DataAnnotations を活用して、モデルに制約を持たせます。
public class UserProfileViewModel
{
[Required]
[StringLength(50, MinimumLength = 3)]
public string Username { get; set; } = string.Empty;
[EmailAddress]
public string? Email { get; set; }
}
Controller では必ず ModelState.IsValid をチェックします。
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult UpdateProfile(UserProfileViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// 正常系の処理
return RedirectToAction("Index");
}
まとめ(チェックリスト)
-
XSS
- Razor の自動エンコードを信頼する
-
Html.Raw()をユーザー入力に使わない
-
CSRF
- フォームには
@Html.AntiForgeryToken() - POST には
[ValidateAntiForgeryToken]
- フォームには
-
SQLインジェクション
- 基本は EF Core(LINQ)で安全に
- 生SQLは 必ずパラメータ化(文字列連結は禁止)
-
バリデーション
- DataAnnotations +
ModelState.IsValidを習慣化
- DataAnnotations +
セキュリティ対策は「後付け」ではなく 設計の一部です。
まずはこの基本セットを徹底すると、実務の事故率が大きく下がります。