気づかないうちにウェブサイトが書き換えられているかも?
インターネットを使っていると、色々なウェブサイトを見ますよね。ニュースサイト、ショッピングサイト、SNS… これらのサイトが安全に動いているのは、裏側でたくさんの技術が頑張っているからです。でも、時々、その技術のスキマを狙った攻撃方法が見つかります。その一つが「DOM Clobbering(ドム クロバリング)」と呼ばれるものです。
「なんだか難しそう…」と感じるかもしれませんが、心配いりません!このブログでは、技術的な難しい話はなるべく避けて、DOM Clobberingがどんなものなのか、なぜ注意が必要なのかを、非エンジニアの方にも分かりやすく解説します。😊
DOM Clobberingって何? 🤔
すごく簡単に言うと、DOM Clobberingは「ウェブページの部品(HTML要素)を使って、ウェブサイトを動かしているプログラム(JavaScript)の動きを意図せず変えてしまう」攻撃手法です。
想像してみてください。あなたがレシピ通りに料理をしているとします。レシピには「砂糖 大さじ1」と書いてあります。でも、誰かがこっそりあなたのキッチンにある「砂糖」と書かれたラベルを「塩」の瓶に貼り替えてしまったらどうでしょう? レシピ通りに作っても、出来上がるのはしょっぱい料理になってしまいますよね。🧂
DOM Clobberingもこれと似ています。ウェブサイトはHTMLという言語で見た目が作られ、JavaScriptという言語で動きが制御されています。通常、JavaScriptは特定の名前(変数名)を使って、ウェブページの情報や設定を管理しています。
しかし、HTMLにはid
やname
という「名前」を部品につける機能があります。昔からのウェブブラウザの仕組みで、このHTML部品の名前が、JavaScriptが使っている名前と偶然(または意図的に)同じだった場合、HTML部品がJavaScriptの変数や設定を「上書き」してしまうことがあるのです。これが「Clobbering(めちゃくちゃにする、上書きする)」と呼ばれる理由です。
この攻撃は、悪意のあるスクリプト(プログラムコード)を直接埋め込むわけではないため、一見すると無害なHTMLコードに見えることがあります。そこが厄介な点です。
どんな時に問題になるの? 😥
DOM Clobberingが起こると、ウェブサイトが予期しない動きをすることがあります。例えば…
- 設定の上書き: ウェブサイトの設定情報が書き換えられ、正しく動作しなくなる。
- 機能の妨害: 例えば、フォームの「送信」ボタンが機能しなくなるなど、ウェブサイトの機能が使えなくなる。
- セキュリティ機能のバイパス: 本来ならブロックされるはずの危険な操作(例: クロスサイトスクリプティング(XSS)という別の攻撃)が、DOM Clobberingによって可能になってしまうことがある。
特に、ユーザーが入力した内容(コメントやプロフィールなど)をウェブページに表示する機能があるサイトでは注意が必要です。攻撃者が巧妙に作られたHTMLコードを入力することで、DOM Clobberingを引き起こす可能性があります。
この攻撃は、直接的なスクリプト実行が難しい(例えば、セキュリティ対策でブロックされている)場合でも、HTMLだけでできてしまうことがあるため、防御が難しい側面があります。
実際の事例はあるの? 📰
はい、DOM Clobberingを利用した脆弱性は実際に発見されています。
- Gmail (2020年頃): GoogleのGmailで、メールの内容に特定のHTMLを埋め込むことでDOM Clobberingが発生し、セキュリティ機能の一部をバイパスできる脆弱性が見つかりました。
- Google Analytics (2020年頃): 同じくGoogleのサービスであるAnalyticsでも、同様の脆弱性が報告されています。
- JavaScriptライブラリ/バンドラー (2024年など): ウェブ開発でよく使われるRollupやViteといったツールでも、DOM Clobberingによって意図しないスクリプトが読み込まれる可能性のある脆弱性が報告・修正されています。
これらの事例は、大手サービスや広く使われているツールであっても、DOM Clobberingのリスクが存在することを示しています。
どうやって防ぐの? (開発者向け) 🛡️
ウェブサイトを作る開発者の皆さんは、DOM Clobberingを防ぐために以下のような対策を考えることができます。
対策 | 簡単な説明 |
---|---|
HTMLサニタイズの強化 | ユーザーが入力したHTMLから、id やname 属性を削除するか、安全な名前に書き換える(例: user_input_xxx のように接頭辞をつける)。DOMPurifyのようなライブラリが役立ちます。 |
グローバル変数の使用を避ける | JavaScriptで安易にグローバル変数(どこからでもアクセスできる変数)を使わず、スコープ(影響範囲)を限定する。let やconst を使い、関数やブロック内に変数を閉じ込める。 |
厳密な型チェック | 変数が期待する型(例えばオブジェクト)であるか、null でないかをしっかり確認してから使う。typeof variable === 'object' && variable !== null のようなチェックを行う。 |
Object.freeze() の利用 |
重要な設定オブジェクトなどがHTML要素によって上書きされないように、Object.freeze() を使ってオブジェクトを「凍結」する。 |
安全なDOM操作 | id やname 属性値に頼らず、document.getElementById() やdocument.querySelector() などを適切に使う。特にdocument.currentScript のようなプロパティは、使用前に本当にscript 要素であるかを確認する。 |
Content Security Policy (CSP) | CSPを設定し、信頼できるドメインからのみスクリプトを読み込むように制限することで、万が一DOM Clobberingによって外部スクリプトが読み込まれそうになっても、それをブロックできる場合があります。 |
完璧な対策というのは難しいですが、これらの方法を組み合わせることで、リスクを大幅に減らすことができます。
簡単なコード例を見てみましょう(これはJavaScriptの例です):
// 悪い例:グローバル変数configがHTML要素で上書きされる可能性がある
let config = window.config || { defaultUrl: '/default.js' };
let script = document.createElement('script');
script.src = config.defaultUrl; // もし があれば、href属性が使われてしまう!
document.body.appendChild(script);
// 良い例:変数がオブジェクトであることを確認する
let configData = window.config;
let scriptUrl = '/default.js'; // デフォルト値を設定
// configDataがnullでなく、HTML要素(DOMノード)でないことを確認
if (typeof configData === 'object' && configData !== null && !configData.nodeType) {
scriptUrl = configData.defaultUrl || scriptUrl;
}
let safeScript = document.createElement('script');
safeScript.src = scriptUrl;
document.body.appendChild(safeScript);
まとめ ✨
DOM Clobberingは、HTMLの仕組みを悪用してJavaScriptの動作を変えてしまう、少し変わった攻撃手法です。非エンジニアの方にとっては直接関係ないように思えるかもしれませんが、私たちが普段使うウェブサイトの安全性に関わる問題です。
開発者は、ユーザーからの入力を適切に処理し、安全なコーディングを心がけることで、このリスクに対応しています。ウェブサイトを使う私たちも、怪しいリンクをクリックしない、ソフトウェアを最新の状態に保つなど、基本的なセキュリティ対策を続けることが大切です。🛡️
コメント