ApacheとPHPの双方でレスポンスヘッダを設定する実験

公開:2020/10/01
更新:2020/10/02
3 min読了の目安(約3400字TECH技術記事

はじめに

X-Frame-Options[1]、X-Content-Type-Optionsなど、セキュアなウェブアプリケーションのために、設定しておくべきとされるヘッダはいくつか存在します。しかし、世の中のHTTPレスポンスヘッダを見ているとこのヘッダの設定値が二重になっていたり二段になっていたりします。この影響と原因を考察しました。

実例

X-Frame-Optionsが二重になっている例

X-Frame-Options: SAMEORIGIN, SAMEORIGIN

多くの場合これでも問題ありません。しかしIEはこれを無視し、iframeでの読み込みが許可されてしまいます。何より見た目が良くありません。

X-Frame-Optionsが二段になっている例

X-Frame-Options: SAMEORIGIN
X-Frame-Options: DENY

IEは上側を優先します。FirefoxやChromeはより厳しいほう(DENY)を優先します。どちらにしても別のオリジンからは読み込まれなくなるので、実際に問題になることはほぼ無いでしょう。設定値が同じなら想定外の動作をすることはありません。でもなんだか見た目が良くありません。

実験

実験内容

Apacheのヘッダ設定には思いのほか多くのオプションが用意されています。網羅的に知りたい場合、日本語版では書き切れていないので英語版[2]を見てください。
これを参考に以下の設定で実験しました。なお、xを大文字と小文字で使い分けていますが、レスポンスヘッダのフィールド名は大文字小文字を区別しません(RFC2616)[3]ので問題ありません。
Apacheの設定

Header set X-PandA-header-test-set "Apache"
Header append X-PandA-header-test-append "Apache"
Header add X-PandA-header-test-add "Apache"
Header merge X-PandA-header-test-merge "Apache"

Header always set X-PandA-header-test-set "alwaysApache"
Header always append X-PandA-header-test-append "alwaysApache"
Header always add X-PandA-header-test-add "alwaysApache"
Header always merge X-PandA-header-test-merge "alwaysApache"

PHPのコード

header('x-PandA-header-test-set: PHP');
header('x-PandA-header-test-append: PHP');
header('x-PandA-header-test-add: PHP');
header('x-PandA-header-test-merge: PHP');

結果

HTTP/1.1 200 OK
Date: Sun, 20 Sep 2020 07:46:21 GMT
Server: Apache
X-PandA-header-test-set: alwaysApache
X-PandA-header-test-append: alwaysApache
X-PandA-header-test-add: alwaysApache
X-PandA-header-test-merge: alwaysApache
~省略:他のフィールド~
x-PandA-header-test-set: Apache
x-PandA-header-test-append: PHP, Apache
x-PandA-header-test-add: PHP
x-PandA-header-test-merge: PHP, Apache
X-PandA-header-test-add: Apache
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8

結果について

alwaysの無いsetではヘッダが上書きされ、PHPの設定が消えました。alwaysの無いappendとmergeではヘッダが二重になりました。addではそれぞれが生きています。X-Frame-Optionsが二重になっているウェブアプリでは以下のような設定になっているのかもしれません。
Apache

Header append X-FRAME-OPTIONS "SAMEORIGIN"

PHP

header('x-Frame-Options: SAMEORIGIN');

alwaysを付けた場合は二段になりますが、前述したとおり、問題になることはほぼ無いでしょう。

推奨される設定

IPAの資料[4]にはこう記されています。

Header always append X-FRAME-OPTIONS "DENY"

alwaysとappendで設定していますね。この通りにしておけば二重にはならないはずです。ただし、二段にはなります。
MDN[5]ではsetを使っています。

Header always set X-Frame-Options "SAMEORIGIN"

※DENYの場合

Header set X-Frame-Options "DENY"

DENYの方はalwaysがありませんが、appendではなくsetなのでPHPと競合した場合、上書きします。二重にならず、きれいに収まりそうです。

原因の考察

二重になってしまった原因を考察しました。あくまで私の推測です。

  • 二重の原因
    • 慌てていてalwaysを書き忘れた。
    • もともとヘッダの設定方法を知っていたのでIPAなどの信頼できる資料を見ずに設定した。
  • 二段の原因
    • とりあえず入れとけ、とApacheとPHPの両方に設定した。
    • Apacheでもともと設定していたところに、PHPのOSSをそのまま導入したので中身について関知していなかった。
    • それぞれ別の人物が勝手に設定した。

OSSについて、例えばWordPressは2011年から追加[6]していたようです。気にせずアップデートして「いつの間にか」ってこともあるのかもしれませんね。

参考資料

脚注
  1. RFC 7034 - HTTP Header Field X-Frame-Options
    https://tools.ietf.org/html/rfc7034 ↩︎

  2. Apache Module mod_headers
    http://hobbit.ddo.jp/manual/en/mod/mod_headers.html ↩︎

  3. RFC 2616 - Hypertext Transfer Protocol
    https://tools.ietf.org/html/rfc2616 ↩︎

  4. IPA:知らぬ間にプライバシー情報の非公開設定を公開設定に変更されてしまうなどの「クリックジャッキング」に関するレポート
    https://www.ipa.go.jp/files/000026479.pdf p.10 ↩︎

  5. X-Frame-Options - HTTP | MDN
    https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/X-Frame-Options ↩︎

  6. Version 3.1.3 WordPress.org
    https://wordpress.org/support/wordpress-version/version-3-1-3/ ↩︎