ペンリジェント・ヘッダー

フロントエンドを安全に:更新されたDOMベースのXSSチートシート

はじめに

DOMベースのXSSチートシートは以下の通り。 参考文献 クライアント側のスクリプト・インジェクションの場所を特定し、防止し、自動化したい場合。要するに、ユーザーが制御する入力 ( ソース)は危険なAPI(a シンクを使用)、安全なパターンに置き換える。 テキストコンテンツ, createElementまたはサニタイザー)を使用し、ビルド、ランタイム、およびペンテストのワークフローにチェックを統合します。DOM XSSは完全にブラウザで発生し、従来の多くのサーバサイドのフィルタをバイパスするため、フロントエンドが最後の防衛ラインとなり、ほとんどのチームがまだ自動化を欠いている場所となります。

DOMベースのXSSとは何か?

PortSwiggerによると、DOMベースのクロスサイト・スクリプティングは以下のような場合に発生する。 「JavaScriptは、URLのような攻撃者が制御可能なソースからデータを受け取り、次のような動的コード実行をサポートするシンクに渡す。 eval() または インナーHTML." ポーツウィガー・ネット OWASP DOM-based XSS Prevention Cheat Sheet(OWASPのDOMベースのXSS対策チートシート)では、ストアド/リフレクテッドXSSとの主な違いは以下の通りであると強調している。 実行時クライアント側インジェクション. cheatsheetseries.owasp.org+1

シングルページアプリ(SPA)、サードパーティ製ウィジェットの多用、ダイナミックDOMの構築など、最新のアプリケーションではリスクが増大します。ペイロードがサーバーログに到達しない可能性があり、従来のWAFでは見逃してしまう可能性があります。 フラグメント識別子, ポストメッセージフローあるいは ウィンドウ名と、いずれも一般的な情報源である。この変化を認識することが、セキュリティの成熟度を測る第一歩となる。

脅威のマッピング:発生源→吸収源

セキュアコーディングは、次のようなメンタルマップから始まる。 ソース (攻撃者の入力が入る)と 流し台 (実行される)。あるセキュリティ・ブログはこうまとめている: "ソースとは、ウェブページ上でユーザー入力が追加されるあらゆる場所のことである......シンクとは、ソースに挿入されたデータが移動する場所のことである......サニタイズされていなければ、DOMベースのXSS脆弱性につながる可能性がある。" ミディアム

以下は、ワークステーションやレビュー・チェックリストに置いておくべきコンパクトな表である:

ソース(エントリーポイント)シンク(危険なAPI)
location.hash, location.search, URLSearchParamsinnerHTML、insertAdjacentHTML、outerHTML
ポストメッセージ ウィンドウ名eval(), new Function(), setTimeout(string)
document.referrer, localStorage, sessionStoragesetAttribute('on...'), element.src = ...
未検証のサードパーティ製ウィジェット・データDOMの挿入や暗黙的なコードの実行

OWASPが強調しているように、単一のテクニックでXSSを防ぐことはできない。適切なシンク、エンコーディング、サニタイズ、安全なAPIを組み合わせる必要がある。 cheatsheetseries.owasp.org

コードと修正による実世界の攻撃パターン

例A - URLフラグメントによるjQueryセレクタ・インジェクション

脆弱なスニペット:

js

$(window).on('hashchange', () => {.

const target = $(location.hash); // ユーザー制御

target[0].scrollIntoView();

});

攻撃者は https://site/page.html#<img src="x" onerror="alert(1)"> - jQueryはハッシュをHTML/セレクタとして扱い オンエラー トリガー

修正する:

js

const raw = location.hash.slice(1);

const safeId = /^[A-Za-z0-9_-]+$/.test(raw) ? raw : null;

if (safeId) { {.

コンスtarget = document.getElementById(safeId);

if (target) target.scrollIntoView();

}

キー:検証、ハッシュをHTMLではなく識別子として扱う。

例B - postMessage → eval チェーン

脆弱なスニペット:

js

window.addEventListener('message', e => {)

eval(e.data); // 危険

});

修正版:

window.addEventListener('message', event => {)

if (event.origin !== '') return;

を試す。

msg = JSON.parse(event.data);

handleMessage(msg);

をキャッチする。

console.warn('Invalid message format');

}

});

避ける 評価オリジンをチェックし、安全なパージングを使用する。

例C - マークダウン・コンテキストにおけるエディター/プレビューXSS

傷つきやすい:

js

preview.innerHTML = marked(userInput);

安全だ:

js

DOMPurify を 'dompurify' からインポートする;

const dirty = marked(userInput);

const clean = DOMPurify.sanitize(dirty);

preview.innerHTML = clean;

ユーザーが作成したHTMLを許可する場合は、サニタイズが必要です。

展開可能な実装:運用を可能にする

安全なDOMヘルパー safe-dom.js

js

DOMPurify を 'dompurify' からインポートする;

export function setSafeHTML(el, dirty) {.

const clean = DOMPurify.sanitize(dirty, {)

ALLOWED_TAGS:['b','i','a','p','ul','li','code','pre','img']、

ALLOWED_ATTR: ['href','src','alt','title','rel']、

FORBID_ATTR: ['onerror','onclick','style']。

});

el.innerHTML = clean;

}

エクスポート関数 setText(el, text) { {.

el.textContent = String(text ?? '');

}

export function safeSetAttribute(el, name, val) {.

if (/^on/i.test(name)) throw new Error('Event handler attribute not allowed');

el.setAttribute(name, String(val));

}

このライブラリを使用して、安全なDOM操作を一元化し、人的ミスを減らします。

静的エンフォースメント - ESLint サンプル

js

// .eslintrc.js

ルールに従います:{

'no-restricted-syntax':[

エラー」、

{ selector:"AssignmentExpression[left.property.name='innerHTML']", message:"safe-dom.setSafeHTMLまたはtextContentを使用してください。"},

{ selector:"CallExpression[callee.name='eval']", message:"Avoid eval()" }、

{ selector:"CallExpression[callee.property.name='write']", message:"document.write()を避ける" }。

]

}

コミット前フック (ハスキー, 前後期)で危険なパターンをブロックする。

CI / Puppeteerテスト - GitHub Actions

.github/workflows/dom-xss.yml はPuppeteerのテストを誘発する:

// tests/puppeteer/dom-xss-test.js

js

const puppeteer = require('puppeteer');

(非同期()=>{

const browser = await puppeteer.launch();

const page = await browser.newPage();

const logs = [];

page.on('console', msg => logs.push(msg.text()));

await page.goto(${URL}/page.html#)<img src="x" onerror="console.log("XSS")">);

await page.waitForTimeout(1000);

if (logs.some(l=>l.includes('XSS'))) process.exit(2);

browser.close() を待つ;

})();

検出で失敗。

ランタイム・モニタリング - MutationObserver

js

(function(){)

const obs = new MutationObserver(muts=>{)

muts.forEach(m=>{

m.addedNodes.forEach(n=>{)

if(n.nodeType==1){。

const html = n.innerHTML || '';

if(/on(error|click|load)|<scriptb/i.test(html)){。

navigator.sendBeacon('/_monitoring/xss', JSON.stringify({)

url: location.href, snippet: html.slice(0,200)

}));

}

}

});

});

});

obs.observe(document.documentElement, {childList:true, subtree:true});

})();

予期せぬDOM注入を警告するステージングに有用。

ブラウザのセキュリティ強化 - CSPとTrusted Types

CSPヘッダー:

pgsql

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-XYZ'; object-src 'none'; base-uri 'self';

トラステッド・タイプのスニペット

js

window.trustedTypes?.createPolicy('セーフポリシー', {)

createHTML: s => { throw new Error('Direct HTML assignment blocked'); }、

createScript: s => { throw new Error('Direct script creation blocked'); }.

});

これはデフォルトで信頼できないシンクを拒否する。

第三者によるスクリプトの安全性 - SRI

バッシュ

openssl dgst -sha384 -binary vendor.js | openssl base64 -A

用途 をピンして検証する。

自動化のためのPenligentとの統合

もしあなたのチームがPenligentを使っているなら、DOM XSS対策を継続的なパイプラインに昇格させることができます。Penligentの調査記事では、次のように指摘しています。 "ランタイム・テイント・トラッキングによってDOMベースのXSSを検出する......サーバーサイドのテクニックでは、クライアントサイド・インジェクションを確実に捉えることはできない。" 寡黙

ワークフローの例:

  1. CIでは、ルールセットでPenligentスキャンをトリガーする。 ドムエックスエスのようなペイロードを提供する。 #<img src="x" onerror="alert(1)">.
  2. Penligentはヘッドレスフローを実行し、PoCを生成し、Webhook経由で調査結果を返す。
  3. CIによる分析結果:重大度≧高であれば、ビルドを失敗させ、PRにペイロード+シンク+修正勧告の注釈をつける(例えば、「place」)。 インナーHTMLsafe-dom.setSafeHTML).
  4. 開発者が修正し、CIを再実行し、緑色のときだけマージする。

これにより、参照(このカンニングペーパー)→コードポリシー→自動検出→組織的修正というループが完成する。

結論

フロントエンドはもはや「単なるUI」ではない。それは 攻撃表面.このチートシートでは、クライアントサイドインジェクションの理解、危険なシンクの置き換え、安全なヘルパーライブラリの構築、静的/CI/実行時検出の導入、Penligentのようなプラットフォームによる自動化について説明します。次のステップ: 禁止されているシンク (インナーHTML, 評価)を採用する。 セーフドム ライブラリ、lint ルールの適用、ヘッドレス・テストと実際のペンテスト・ロジックの統合、本番/ステージングの監視、サードパーティ・リソースのピン留めなどです。DOM XSSを保護することは、DOM XSSを以下のようにすることです。 不可能 偶然に頼るのではなく、すり抜けるために。

記事を共有する
関連記事