Edited at

WEBページをセキュアにするHTTPヘッダーを設定しよう

セキュリティに関する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