セキュリティに関するHTTPヘッダーとPHPにおけるその設定方法のまとめです。
HSTS(HTTP Strict Transport Security)
次から接続するときはHTTPSで接続してくださいとお願いする仕組みです。HTTPSでの接続を強制したいときに用います。
header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');
オプション
-
max-age
どのくらいの期間(単位は秒)HTTPSでの接続をお願いするか -
includeSubDomains
このオプションをかくとサブドメインにも適用される -
preload
プレロード設定(後述)を行ったら追記する
プレロードについて
HTSTはHTTPSでの接続を強制したいときに用いるのですが、それでもなお初回サイト訪問時のアクセスはHTTPになる可能性があります。初回の接続もHTTPSに強制したい。そこで用いられるのがこのプレロードで、ブラウザが最初から「このサイトはHTTPSで繋いでくださいね」とユーザーに働きかけてくれます。登録は簡単でこちらにドメインを入力するだけで、ユーザーがブラウザをアップデートした時点から有効になります(アップデート時にユーザーにプレロードリストがインストールされるため)。
HPKP(HTTP公開鍵ピンニング:HTTP Public Key Pinning)
2回目以降の接続時に、以前の接続の時と同じサーバ証明書であるかを確認する仕組みです。公開鍵をピン留めすることで証明書の不正な変更を検知することができます。なお現在Chromeの最新版ではHPKPの対応は打ち切られています。
header('Public-Key-Pins: pin-sha256="<サーバ証明書>"; pin-sha256="<中間認証局以上の証明書>"; max-age=5184000; includeSubDomains; report-uri="<report_uri>"');
オプション
Public-Key-Pins
ヘッダーとPublic-Key-Pins-Report-Only
ヘッダーがあり、前者は不正な証明書を検知した時点でアクセスを遮断し、後者は検知したら報告のみ行い遮断は行わない。
-
pin-sha256
Base64でエンコードされた証明書の公開鍵情報 -
max-age
ピン留めする期間(単位は秒) -
includeSubDomains
このオプションをかくとサブドメインにも適用される -
report-uri
不正を報告する送信先
max-age
を設定するときの注意点
一度ピン留めされた公開鍵の情報はmax-age
の期間ユーザーに保存されるため、もし間違った公開鍵情報を登録するとその間アクセスが遮断されてしまいます。ですので、まずはmax-age
は小さい値(HPKPの特性上長い方が好ましいですが)で、あるいはPublic-Key-Pins-Report-Only
で試してみることをお勧めします。
公開鍵の登録について
上でも述べたように、公開鍵の情報が誤っていた場合はmax-age
で指定した期間サイトへのアクセスが遮断されます。多くのサーバ証明書の更新は一年サイクルで、この時に適切に変更を行わないとサイトにアクセスできなくなるわけです。ですから念のため、より更新サイクルの長い中間認証局以上の証明書を予備で書いておくことをお勧めします。
AWSの無料証明書を使ってピンニングする
AWSの無料証明書発行サービスである Amazon Certificate Manager で取得した証明書を用いてHPKPを設定する方法について書きました。
【AWS】無料のサーバ証明書を公開鍵ピンニングする
CSP(Content Security Policy)
ページ内で読み込むリソースに制限を設ける仕組みです。読み込むリソースの出所を予めリストアップし、それ以外のロードを遮断することで、予期せぬスクリプトの実行などを防ぐことができます。
header("Content-Security-Policy: default-src 'self'; script-src 'self' https://www.google-analytics.com upgrade-insecure-requests report-uri <report_uri>");
オプション
Content-Security-Policy
ヘッダーとContent-Security-Policy-Report-Only
ヘッダーがあり、前者は違反したリソースを全て遮断、後者は指定したURIに違反報告のみ行い遮断は行わない。導入時はにReport-Onlyの方がいいかと思います。
-
Fetchディレクティブ
script-src
など、リソースの種類ごとに出所を指定する。 -
report-uri
違反報告の送信先 -
upgrade-insecure-requests
これをかくとhttpと書かれたリソースに対してもhttpsでアクセスしに行く -
block-all-mixed-content
これをかくとhttpのリソースはそもそも読み込まない
より詳しく
個々のページによって必要なリソースが変わってくるので、詳しくはこちらに書きました。
WEBページをコンテントセキュリティポリシー(CSP)に対応させたかった話 - Qiita
X-XSS-Protection
XSS攻撃を検知する仕組みです。
header("X-XSS-Protection: 1; mode=block; report=<report_uri>");
オプション
0でXSSフィルタリングを無効化、1で有効化します
-
mode=block
XSS攻撃を検知したらページの読み込みを止める -
report
XSS攻撃を検知したときにその内容を送信するURI
X-Content-Type-Options
ファイルの内容からファイルの種類を決定させるかどうか。以下のように書けばテキストで書かれたscript
タグやstyle
タグが勝手に解釈されることはありません。
header("X-Content-Type-Options: nosniff");
X-Frame-Options
ページをiframeに読み込ませるかどうか。
header("X-Frame-Options: DENY");
オプション
-
DENY
全てのサイトに対して読み込みを禁ずる -
SAMEORIGIN
同じオリジン内のみ読み込みを許可する -
ALLOW-FROM <url>
指定したurlからの読み込みを許可する
ReportURI
上記のreport_uri
系のディレクティブに書くurlですが、いちいちレポートの受け口を用意するのは面倒かと思います。そこでReportURIというサービスを用いると簡単にレポートを確認することができます。無料で月10,0000件まで見れるのでオススメです。
参考
HTTP Strict Transport Security - Web セキュリティ | MDN
HTTP Public Key Pinning (HPKP) - Web セキュリティ | MDN
Content-Security-Policy - HTTP | MDN
X-Frame-Options - HTTP | MDN