C# Tips | 文字列処理:HTMLエスケープ

C# C#
スポンサーリンク

はじめに 「HTMLエスケープ」は“文字列をHTMLとして誤解させないための防御”

Web画面を作るとき、ユーザーが入力した文字列をそのままHTMLに埋め込むと、とても危険です。
なぜなら、<script><b> のような「HTMLとして意味を持つ記号」が、そのまま“タグ”として解釈されてしまうからです。

HTMLエスケープは、一言でいうと、

「ただの文字列」を「HTMLとして解釈されない安全な文字列」に変換する処理

です。

例えば、次のような文字列を考えます。

こんにちは <b>太郎</b> さん

これをそのままHTMLに出すと、「太郎」が太字になります。
でも、「ユーザーが入力したものは“ただのテキスト”として表示したい」なら、

こんにちは &lt;b&gt;太郎&lt;/b&gt; さん

のように変換しておく必要があります。
これが「HTMLエスケープ」です。


なぜHTMLエスケープが必要なのか(XSSの入り口をふさぐ)

「タグとして動いてほしくないもの」をただの文字にする

HTMLエスケープの一番大事な目的は、XSS(クロスサイトスクリプティング)を防ぐことです。

例えば、ユーザーがこんな文字列を入力したとします。

<script>alert('XSS');</script>

これをエスケープせずに画面に埋め込むと、
ブラウザは「ただの文字」ではなく「JavaScriptコード」として実行してしまいます。

でも、HTMLエスケープしておけば、

&lt;script&gt;alert('XSS');&lt;/script&gt;

となり、ブラウザは「タグ」ではなく「テキスト」として表示します。
つまり、「危険なものを“ただの文字”に変える防御壁」がHTMLエスケープです。


C#での基本:HtmlEncode(HTMLエスケープ)を使う

代表的な2つのAPI

C#(.NET)でHTMLエスケープをするには、主に次の2つを使います。

  • System.Web.HttpUtility.HtmlEncode
  • System.Net.WebUtility.HtmlEncode

Webアプリ(ASP.NET系)なら HttpUtility がよく出てきますが、
最近は WebUtility のほうが依存が少なくて扱いやすいです。

ここでは WebUtility.HtmlEncode を使った例で説明します。

using System;
using System.Net;

public static class HtmlEscapeUtil
{
    public static string Escape(string? value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return string.Empty;
        }

        return WebUtility.HtmlEncode(value);
    }
}
C#

動作例

Console.WriteLine(HtmlEscapeUtil.Escape("こんにちは <b>太郎</b> さん"));
// こんにちは <b>太郎</b> さん

Console.WriteLine(HtmlEscapeUtil.Escape("<script>alert('XSS');</script>"));
// <script>alert('XSS');</script>
C#

ここで注目してほしいのは、
<> だけでなく、シングルクォート '&#39; のように変換されていることです。
これにより、HTML属性の中に埋め込んだときの安全性も高まります。


どんな文字がエスケープされるのか

代表的な変換例

HTMLエスケープでは、主に次のような文字が変換されます。

  • <&lt;
  • >&gt;
  • &&amp;
  • "&quot;
  • '&#39;(または &apos;

これらは、HTMLの中で特別な意味を持つ記号です。
そのまま出すと「タグの開始」「属性の区切り」「エンティティの開始」などとして解釈されてしまいます。

エスケープすることで、「これは記号じゃなくて“文字”ですよ」とブラウザに伝えることができます。


HTMLエスケープと逆変換(デコード)

HtmlDecode で元に戻せる

エスケープした文字列を、元の文字列に戻したい場面もあります。
そのときは、HtmlDecode を使います。

using System.Net;

string encoded = "こんにちは <b>太郎</b> さん";
string decoded = WebUtility.HtmlDecode(encoded);

Console.WriteLine(decoded);
// こんにちは <b>太郎</b> さん
C#

HtmlEncodeHtmlDecode はセットで覚えておくと便利です。


実務での設計ポイントと注意点

どこでエスケープするかを「層」で決める

よくある失敗は、「どこでエスケープするか」がバラバラになることです。

  • DBに保存する前にエスケープする
  • 画面に出す直前にエスケープする
  • どこかのサービス層でエスケープする

これが混ざると、「二重エスケープ」「エスケープ漏れ」が起きやすくなります。

おすすめは、

「DBには“生の値”を保存し、画面に出す直前でエスケープする」

というルールに統一することです。

  • DB:ユーザーが入力したそのまま(ただしバリデーションは別途)
  • HTML出力:ビューやテンプレート側で必ずエスケープ

こうしておくと、「どの層で何をしているか」が明確になり、バグが減ります。

二重エスケープに注意する

例えば、すでにエスケープされた文字列に、さらに HtmlEncode をかけるとこうなります。

string once = WebUtility.HtmlEncode("<b>太郎</b>");
// once: <b>太郎</b>

string twice = WebUtility.HtmlEncode(once);
// twice: &lt;b&gt;太郎&lt;/b&gt;
C#

画面に twice を出すと、&lt;b&gt;太郎&lt;/b&gt; がそのまま表示されてしまい、
「タグとしてもテキストとしても中途半端」な状態になります。

なので、

  • 「この値はすでにエスケープ済みか?」
  • 「この層でエスケープするのは正しいか?」

を意識して設計することが大事です。


HTMLエスケープユーティリティとしてまとめる

「とりあえずこれを通せば安全」という窓口を1つ作る

プロジェクト全体で使う「HTMLエスケープ窓口」を1つ用意しておくと、
あとからの変更や調整がとても楽になります。

using System.Net;

public static class HtmlSafe
{
    public static string Encode(string? value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return string.Empty;
        }

        return WebUtility.HtmlEncode(value);
    }

    public static string Decode(string? value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return string.Empty;
        }

        return WebUtility.HtmlDecode(value);
    }
}
C#

ビューやテンプレート側では、常にこの HtmlSafe.Encode を通すようにしておけば、

  • 将来、別のエスケープ方法に変えたくなった
  • ログ出力時だけは別のルールにしたい

といったときも、このユーティリティを直すだけで済みます。


まとめ 「HTMLエスケープユーティリティ」は“文字列を安全に画面へ渡すための最後のフィルタ”

HTMLエスケープは、Webアプリにおける超基本かつ超重要な防御テクニックです。

押さえておきたいポイントは、

  • HTMLエスケープは「タグやスクリプトとして解釈されないようにする」ための変換
  • C#では WebUtility.HtmlEncode / HtmlDecode を使うのが基本
  • <, >, &, ", ' などの記号がエスケープされる
  • DBには生の値を保存し、「画面に出す直前でエスケープ」に統一すると設計がきれいになる
  • 二重エスケープを避けるために、「どこでエスケープするか」をユーティリティ+ルールで固定する

ここまで理解できれば、「なんとなくエスケープしている」段階から一歩進んで、
“XSSを意識した、安全な文字列処理の設計”を、自分のC#ユーティリティとして形にしていけるようになります。

タイトルとURLをコピーしました