こんにちは。現場の最前線でコードと格闘し、時にインシデントの火消しに奔走しているエンジニアの皆さん、お疲れ様です。
今日は、Webセキュリティの「基本中の基本」でありながら、意外と見落としがちな「javascript:スキーム」の攻撃と対策についてお話しします。
「XSS(クロスサイトスクリプティング)」という言葉を聞くと、なんだか複雑で難しそうなイメージを持つかもしれません。でも大丈夫、まずは身近な「家の防犯」に例えて、その正体を暴いていきましょう。
—
1. なぜ「javascript:」が危険なのか?(泥棒の侵入経路)
皆さんの家には「玄関のドア」がありますよね。このドア(URL欄やリンク属性)には、本来「http://」や「https://」といった、信頼できる場所への行き先だけを書くはずです。
しかし、もし誰かが勝手にあなたの家の玄関に「このドアを開けたら、勝手に家の中の金庫を空けて良い」という魔法のスイッチを仕込んだらどうなるでしょう?
Webの世界でいう「javascript:」は、まさにその「魔法のスイッチ」です。
本来、リンクをクリックすると別のページに飛ぶはずなのに、そこに javascript:alert('ハック完了!') のようなコードが書かれていると、ブラウザは「ああ、これはページ移動ではなく、今すぐプログラムを実行しろってことね!」と勘違いして、あなたのWebサイト上で勝手に悪意ある命令を実行してしまいます。これが、XSSの恐ろしいところです。
—
2. 攻撃者が狙う「盲点」
多くの開発者は「HTMLのタグをエスケープすれば大丈夫!」と考えがちです。確かに、タグそのものを無効化するのは重要ですが、攻撃者はもっと賢いです。
彼らは、 タグの href 属性の中に、こっそりと javascript: を忍び込ませます。
ユーザーがこのリンクを押すと、その瞬間にCookie(ログイン情報など)が攻撃者のサーバーへ送信されてしまいます。入力チェックで < や > を防いでいても、href の中身まではチェックしていないことが多く、ここが最大の「盲点」になるわけです。
---
3. 防御の鉄則:ホワイトリスト方式を採用する
では、どう守ればいいのでしょうか? 答えは単純です。「許可されたもの以外は、徹底的に排除する」という「ホワイトリスト方式」です。
「http://」や「https://」から始まるものだけを通し、それ以外(javascript:など)は全部拒否する。これが最強の防犯対策です。
実装例:JavaScriptでの検証コード
現場で使える、シンプルかつ強力なバリデーション関数を紹介します。
/
- URLが安全かどうかを判定する関数
- @param {string} url - チェックしたいURL
- @returns {boolean} - 安全ならtrue、危険ならfalse
/
function isSafeUrl(url) {
// 1. まず小文字に変換(大文字小文字の揺らぎ攻撃を防ぐ)
const lowerUrl = url.toLowerCase().trim();
// 2. ホワイトリスト:これらで始まるものだけを許可する
// 「javascript:」は決して含まれていないので、自動的に拒否される
const allowedProtocols = ['http:', 'https:', 'mailto:'];
try {
const parsedUrl = new URL(lowerUrl);
return allowedProtocols.includes(parsedUrl.protocol);
} catch (e) {
// URLとして解釈できない怪しい文字列は「危険」とみなす
return false;
}
}
// 使用例
console.log(isSafeUrl("https://google.com")); // true
console.log(isSafeUrl("javascript:alert(1)")); // false (ブロック!)
---
4. 防御は「二重、三重の鍵」で
開発者の皆さんに覚えておいてほしいのは、「プログラムのチェックだけに頼りすぎない」ということです。泥棒も鍵をこじ開けるプロです。アプリ側のチェックに加えて、ブラウザの力も借りましょう。
CSP(Content Security Policy)というヘッダーをご存知でしょうか? これを設定しておくと、たとえコードに隙があっても、ブラウザ側で「javascript:スキームの実行は禁止!」と強制的に止めてくれます。
サーバーのレスポンスヘッダーに以下のように設定するだけで、防犯レベルが劇的に上がります。
Content-Security-Policy: default-src 'self'; script-src 'self';
※ unsafe-inline を許可しないのがポイントです。
---
最後に:セキュリティは「終わりなき旅」
「ここまで対策したから100%安全!」と宣言できるエンジニアはいません。しかし、今回お伝えした「URLのスキームをホワイトリストで絞る」という意識を持つだけで、皆さんの作るWebサイトは、攻撃者にとって「非常に攻めにくい要塞」になります。
セキュリティは、難しい技術を詰め込むことではなく、「どうすれば相手の意図を無効化できるか」という想像力から始まります。
まずは今日、ご自身の書いているコードの href 属性を見直してみてください。「これ、本当に安全なURLだけが通るようになっているかな?」と。その小さな気づきが、ユーザーの情報を守る最大の盾になりますよ。
一歩ずつ、一緒に強くなっていきましょう!応援しています。
コメント