全ページに SAMEORIGIN を付けようとして止まった

ウェブの応答に X-Frame-Options というヘッダを付けると、ほかのサイトの iframe に自分のページを埋め込ませないようにできます。悪意のあるページが透明な iframe で他サイトの画面を重ね、利用者に意図しないクリックをさせる。そんなクリックジャッキングへの、よくある固めの一つです。

私たちもこれを入れようとしました。値は SAMEORIGIN で、全ページに一律に付ける方針です。手間が少なく、書き漏らしも出にくい。一番簡単に見える方法でした。

ところが、ここでいったん手を止めました。理由は、私たち自身のスマホアプリにあります。

このアプリは、一部の画面でサーバの HTML を、アプリの中の iframe で開いています。WebView を使うハイブリッドのアプリでは、アプリ自身の画面のオリジンが、サーバのドメインとは別になります。SAMEORIGIN は「埋め込む側と埋め込まれる側のオリジンが同じときだけ許す」という指定です。つまり、一律に付けると、自分のアプリが自分のページを開く表示まで「よそからの埋め込み」として扱われ、弾かれてしまいます。弾かれた画面は、白くなります。

クリックジャッキング対策が目的なのに、自分の画面を壊しては意味がありません。そこで、入れる前に実際に起きるかどうかを確かめることにしました。

実ブラウザで確かめたら、画面が真っ白になった

頭の中の理屈だけで「たぶん壊れる」と言っても、判断の材料としては弱いと考えました。そこで実ブラウザで確かめました。

やり方はこうです。アプリ側と同じオリジンの親ページを用意し、そこから本番の画面を iframe で開きます。アプリが実際に画面を開くときの関係を、ブラウザの上で再現した形です。

条件結果
ヘッダなし中身が 3972 字読めた
応答に SAMEORIGIN を 1 行足した同じ画面が真っ白になった

差はヘッダ 1 行だけです。画面も、親ページも、開き方も変えていません。それでも、読めていた 3972 字が、まるごと消えました。

このまま一律に入れていたら、アプリの中の画面が白くなるところでした。確かめずに「よくある固めだから」と入れていたら、気づくのは利用者の画面が白くなってからだったかもしれません。ここは、入れる前に実ブラウザで見ておいて良かった点です。

埋め込みで使う文書だけを対象から外した

直し方は単純です。アプリが埋め込んで使う文書だけを対象から外し、ほかは全部に付けるようにしました。

手間がかかったのは、外す対象を決める部分です。「全部に付ける」の前に、自分のアプリが自分のどのページを埋め込んでいるかを洗い出す必要があります。これはアプリのコードをたどって調べました。埋め込みで開くものと、外のブラウザで開くものを分け、それぞれ確かめています。

この分け方は大事です。外のブラウザで開くページは、iframe の中には入りません。だから SAMEORIGIN を付けても壊れません。壊れるのは、アプリの中の iframe で開くものだけです。ここを混ぜてしまうと、外すべきでないページまで外してしまいますし、逆に外し忘れれば画面が白くなります。

入れたあとは、二つのことを確かめました。

  1. 実ブラウザで、アプリの画面がそのまま映ること。
  2. 固めが効いていること。これはヘッダを見て確かめました。

確かめの項目は 35 項目ありました。結果は、すべて通りました。

そこから決めたこと

ヘッダの固めは、「全部に付ける」が一番簡単に見えます。私たちもそう思って始めました。ただ、自分たちのアプリが自分たちのページを埋め込んでいる所があると、そこが壊れます。

だから、次のように決めました。付ける前に、埋め込み先を探します。そして実ブラウザで、画面が白くならないかを見ておきます。この二つを、固めを入れる手順の一部にします。

この話は X-Frame-Options に限らないと考えています。ほかのサイトから守るための設定は、自分のアプリやシステムも「ほかのサイト」と同じ扱いにしてしまうことがあります。ハイブリッドのアプリのように、自分の画面のオリジンが自分のサーバと別になる作りでは、特にそうです。守る側の設定を足すときは、自分の持ち物がその設定の外側に出ていないかを、先に見たほうがよいと思います。

固めを入れること自体は、これからも進めます。ただし、一律に付けるのではなく、埋め込みの実態を調べてから付けます。壊さずに固めを効かせるには、この順番がよいというのが、今回の結論です。