1. はじめに
Webサイトに関する脆弱性の1つに「Relative Path Overwrite (RPO)」があります。
こんな感じの脆弱性です。
URLを少し工夫してWebページにアクセスすると、そのページ内にある「相対パスで読み込み指定されているCSSファイル」の部分で、CSSファイルの代わりにアクセス対象であるHTMLファイルが読み込まれてしまう(HTMLファイルがCSSファイルとして読み込まれてしまう)。
➡ そのHTMLファイルの中に、うまいことCSSが記述されていると、ちゃんとCSSとして評価されて実行されてしまう(HTMLがQuirksモードで実行されるように記述されている必要もある)。つまり、アクセス対象のHTMLファイルに対して、同じHTMLファイル内のCSSコードが適用される。
➡ そのHTMLファイルの中に「ユーザーが入力した文字列が出力される箇所」があった場合、ユーザーが入力した任意のCSSが実行されることになる!(その箇所がHTMLエスケープされていても、CSSには影響がない)
次では、もう少し具体的にRPOの動作ついて説明します。
2. Relative Path Overwrite (RPO) の動作を説明する
RPOといってもいろいろなタイプがあるようですが、ここで取り上げるのはかなりシンプルなケースになります。
(1) 前提
以下を満たすWebページがあるとします。
- ユーザーが登録した情報が表示される。
- CSSファイルが相対パスで読み込まれている。
- 例:「<link rel=”stylesheet” href=”main.css”>」
- DOCTYPE として「<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>」が出力されている。
- この記述により、HTMLがQuirksモードで実行される。
- URLは「https://example.com/index.html」であるが、「https://example.com/index.html/」にアクセスしても、同じページが表示される。
(2) どうやって問題が起きるか
以下の操作によって、ユーザーが入力した任意のCSSが正常に動作してしまいます。
- ユーザーが登録情報の1つに「{}*{color:blue;}」を登録する。
- 今回は例として「*{color:blue;}」としましたが、この部分に任意のCSSを指定します。
- これが index.html に表示されます。
- ブラウザで「https://example.com/index.html/」にアクセスする。
- 相対パスで指定していたCSSファイルの部分で、ブラウザは /index.html/main.css にリクエストを送るが、サーバーは index.html を返してしまう。
- その index.html には「{}*{color:blue;}」が出力されている。この出力箇所がHTMLエスケープ処理されていたとしても、あくまでHTMLに対するエスケープ処理なので、CSSのエスケープにはならない。
- ブラウザは index.html をレンダリングするが、同時に index.html をCSSとしても利用することになる。
- ブラウザが index.html をCSSとして解釈するかどうかは、「DOCTYPE」「CSSの書き方」の2つが重要です(ブラウザにも依るようですが)。今回はCSSの部分で最初に「{}」と書いており、これによってブラウザはCSSとして解釈してくれる。他にも書き方がある。
- index.html に出力されたCSSが適用されて、index.html が表示される。
ブラウザのデベロッパーツールを使い、「CSSファイルを取得するリクエストのURL」や「そのリクエストが返した内容」を観察するとよいです。
デモページを用意しました。
デモページ
🔗 RPO の実験3. 対策
- 相対パスでCSSを読み込むのはやめましょう。
- DOCTYPE は「<!DOCTYPE html>」と指定すべきです。
- レスポンスヘッダに「X-Content-Type-Options: nosniff」を出力することでも、この脆弱性は避けられるようです。
4. おわりに
今どき、古い DOCTYPE が使われていることはあまりないと思いますが、本記事に書いた仕様のページがあった場合、最新の Chrome でもこの現象が起きてしまうのが怖いところです。