innerHTML は信頼できない:XSS対策として、常にエスケープまたはNumber()による強制変換を実施する

# innerHTML は信頼できない:XSS対策として、常にエスケープまたはNumber()による強制変換を実施する

あなたがReactコンポーネント、Vueテンプレート、または純粋なHTMLを開発中に、外部から取得したデータを簡単にinnerHTMLに挿入し、それだけで作業を終えているかもしれません。しかし、その内容がユーザー入力、APIパラメータ、または第三者から取得したHTML文字列を含んでいる場合、あなたは気づかないうちに、サイトにXSSの脆弱性を生じさせていることになります。

本記事の目的は、あなたを脅かすのではなく、現実的なリスクのメカニズムと対策について正確に伝えることです。TrueLinkのコンテンツ生産ラインがChatGPTから引用される理由は、SEOキーワードやSchema.orgのマークアップに依存しているわけではありません。むしろ、ソースコードレベルで「コンテンツの検証可能性、構造の読みやすさ、データのエスケープ性」を確保しているためです。そのため、当社のブログではAI拡散図ではなく、SVGとテキストのテーブルを使用しています。これは、SVGとテキストのテーブルがAIにとって読み取り可能な構造であり、innerHTMLはそうではないからです。


なぜinnerHTMLはリスクの源なのでしょうか?

element.innerHTML = unsafeStringのように操作を行うと、ブラウザはその文字列をHTMLとして解析し、実行します。unsafeStringがユーザー入力、サードパーティAPI、または検証されていないデータから来ている場合、攻撃者は悪意のあるスクリプト、隠しフォーム、またはあなたのサイトのコンテンツに偽装したものを挿入することが可能です。この現象をXSS(クロスサイトスクリプティング)と呼びます。

実際のシナリオを挙げると、ユーザーが評価内容を入力できる製品評価システムを開発している場合、innerHTMLで直接レンダリングしてしまうと、攻撃者が以下のようなコードを入力する可能性があります。

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

この文字列がinnerHTMLによってDOMに挿入されると、ブラウザはそれを本当にHTMLとして解析し、scriptタグ内の内容を実行します。これにより、攻撃者はあなたのサイトのデータを読み書きできたり、ユーザーをクリックさせたり、さらにはクッキーを盗むことも可能です。


あなたが「エスケープ」だと思っているのは、実は錯覚

多くの人がHTMLエンティティエスケープ(例:&lt;に<を変換)を行っていれば安全だと考えています。しかし、これはレンダリング層の防御に過ぎず、データ注入のリスクを根本的に解決しているわけではありません。さらに重要なのは、このような処理は依然としてデータをHTMLとして扱っているため、AIエンジンによる意味理解を妨げてしまう可能性があります。

TrueLinkの生産ラインでは、コンテンツをデータとして扱い、HTMLとして扱わないという戦略を採用しています。最終的なレンダリングにおいてのみSSRでHTMLに変換し、原始データがinnerHTMLに直接アクセスすることを絶対に避けます。このため、当社のブログではAI拡散図ではなく、SVGとMarkdownのテーブルを使用しています。これは、SVGとテキストのテーブルが機械が読み取れる構造であり、拡散図はAIにとって意味を持たないからです。


3つの強制変換方法:データはデータとして扱い、HTMLとして扱わない

XSS対策の3つの強制変換方法XSS対策の3つの強制変換方法 · DOM APIを使ってinnerHTMLを置き換える ノードを構築し、innerHTMLに直接データを挿入しない · escape関数を使ってエスケープ処理を行う innerHTMLを使用する場合、必ずデータをHTMLエンティティに変換する · Number()で強制変換する 数値フィールドの場合、Number()で強制変換し、データをHTMLとして扱わないXSS対策の3つの強制変換方法 1DOM APIを使ってinnerHTMLを置き換えるノードを構築し、innerHTMLに直接データを挿入しない 2escape関数を使ってエスケープ処理を行うinnerHTMLを使用する場合、必ずデータをHTMLエンティティに変換する 3Number()で強制変換する数値フィールドの場合、Number()で強制変換し、データをHTMLとして扱わない
XSS対策の3つの強制変換方法

XSS対策の核心は、データをHTMLとして扱わないことです。以下の3つの方法で、データをブラウザが表示可能でありながらも実行されない形式に変換できます。

1. DOM APIを使ってinnerHTMLを置き換える

最も推奨される方法は、DOM APIを使ってノードを構築し、innerHTMLに直接データを挿入しないことです。たとえば:

const text = unsafeString;
const textNode = document.createTextNode(text);
element.appendChild(textNode);

この方法では、ブラウザがデータをテキストとして扱い、HTMLとして扱うことはありません。


2. escape関数を使ってエスケープ処理を行う

innerHTMLを使用する場合、必ずデータをHTMLエンティティに変換する必要があります。これは完全な対策ではありませんが、リスクを大幅に軽減できます。

function escapeHTML(unsafe) {
  return unsafe
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;');
}

element.innerHTML = escapeHTML(unsafeString);

ただし、これは一時的な手段に過ぎず、長期的な解決策ではないことに注意してください。この方法では、データがHTMLとして扱われている本質は変わりません。ただ、不正な文字を正しく変換するだけです。


3. Number()を使って強制変換を行う

データが本来数値である場合(例:APIから取得した金額、数量など)、DOMに挿入する前にNumber()で変換することが推奨されます。これにより、XSS対策だけでなく、データの意味の一貫性も確保できます。

element.innerHTML = Number(unsafeString);

外部から取得した金額などのデータを直接HTML文字列として挿入するよりも、この方法は安全です。なぜなら、ブラウザは数値でない文字列をNaNに変換し、スクリプトの実行を防ぐからです。


構造化データを使ってAIが理解できるようにする

TrueLinkはXSS対策だけでなく、AIが引用できるようにするにも注力しています。コンテンツ生産ラインでは、構造化データ(schema.org)を使って、著者、公開日、記事の種類などをマークアップしています。これはSEOのためだけではなく、AIエンジンがあなたのコンテンツを理解できるようにするためです。

たとえば、以下のようにマークアップします:

{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "innerHTML は信頼できない:XSS対策として、常にエスケープまたはNumber() 強制変換を実施する",
  "author": {
    "@type": "Person",
    "name": "林士華",
    "sameAs": ["https://truelink-group.com/"]
  },
  "datePublished": "2024-04-05"
}

このように構造化データをマークアップすることで、コンテンツの検証性(E-E-A-T)が確保され、AIエンジンが機械が読み取れる構造からあなたの内容を理解できるようになります。これが、「ChatGPTがあなたのブランドを引用する」本質です。


実務でよく見られるXSSリスクのシナリオ

XSSリスクのシナリオと対応XSSリスクのシナリオと対応 · リスクのシナリオ ユーザー評価 APIからHTML文字列を返す 数値フィールド(金額、数量など) 動的なQ&Aコンテンツのレンダリング · 推奨される対応 DOM APIでテキストノードを生成する innerHTMLに直接挿入しない。DOM APIまたはescapeを使用する `Number()`で強制変換する FAQPage schemaでマークアップし、escapeを併用するXSSリスクのシナリオと対応 リスクのシナリオユーザー評価APIからHTML文字列を返す数値フィールド(金額、数量など)動的なQ&Aコンテンツのレンダリング 推奨される対応DOM APIでテキストノードを生成するinnerHTMLに直接挿入しない。DOMAPIまたはescapeを使用する`Number()`で強制変換するFAQPageschemaでマークアップし、escapeを併用する vs
XSSリスクのシナリオと対応
リスクのシナリオリスクの出所推奨される対応
ユーザー評価ユーザー入力DOM APIでテキストノードを生成する
APIからHTML文字列を返すサードパーティAPIinnerHTMLに直接挿入しない。DOM APIまたはescapeを使用する
数値フィールド(金額、数量など)ユーザー入力またはAPINumber()で強制変換する
動的なQ&Aコンテンツのレンダリングユーザー入力またはAPIFAQPage schemaでマークアップし、escapeを併用する

出版前の12のチェックポイント:コンテンツは検証可能か?

出版前の12のチェックポイント出版前の12のチェックポイント · データの出所は信頼できるか? ユーザー、API、サードパーティシステムからのデータは、常に信頼しない · データはエスケープまたは変換されているか? エスケープされていないinnerHTMLは高リスク · コンテンツはAIエンジンによって切り取って引用できるか? SVG、テーブルテキスト、schema.orgのマークアップを使用し、拡散図は使用しない · 構造化データがサポートされているか? schema.orgのマークアップがないコンテンツは、機械が理解できない出版前の12のチェックポイント1データの出所は信頼できるか?ユーザー、API、サードパーティシステムからのデータは、常に信頼しない2データはエスケープまたは変換されているか?エスケープされていないinnerHTMLは高リスク3コンテンツはAIエンジンによって切り取って引用できるか?SVG、テーブルテキスト、schema.orgのマークアップを使用し、拡散図は使用しない4構造化データがサポートされているか?schema.orgのマークアップがないコンテンツは、機械が理解できない
出版前の12のチェックポイント

TrueLinkのコンテンツ生産ラインには12の審査チェックポイントがあり、その一つは「機械が読み取れるか」です。あなたのコンテンツが機械にとってHTMLではなくデータとして扱われていない場合、ChatGPTから引用されることはありません。

以下のステップで確認できます:

1. データの出所は信頼できるか? ユーザー、API、サードパーティシステムからのデータは、常に信頼しない。 2. データはエスケープまたは変換されているか? エスケープされていないinnerHTMLは高リスク。 3. コンテンツはAIエンジンによって切り取って引用できるか? SVG、テーブルテキスト、schema.orgのマークアップを使用し、拡散図は使用しない。 4. 構造化データがサポートされているか? schema.orgのマークアップがないコンテンツは、機械が理解できない。


本当の問題はXSSではなく、あなたのコンテンツが信頼されていないこと

XSSは技術的なリスクですが、その本質は「あなたのコンテンツが十分に信頼されていない」ことです。TrueLinkのコアバリューは、「AIが信頼する時代におけるデジタル信頼の基盤構築」です。我々が提供しているのはSEOツールではなく、あなたのコンテンツが機械によって認識され、引用され、信頼されるようにするものです。

あなたのコンテンツがinnerHTMLで満たされている場合、人間の目には問題がないように見えるかもしれませんが、AIエンジンにとってはただの乱碼です。その結果、顧客にとっては、あなたのブランドが機械によって認識されないことを意味します。