IdeaValue

HSTSの設定方法:httpからhttpsへの転送と Strict-Transport-Security

執筆:IDEAVALU運営 · 更新:

HSTS は「このサイトには今後 HTTPS でしか接続しないで」とブラウザに覚えさせる仕組みです。http から https へ転送するだけでは、最初の http の通信が暗号化されないまま残ります。

転送だけでは足りない理由

http:// で開かれたとき、サーバーは https:// への転送を返します。しかし最初の http のリクエストと転送の応答は暗号化されていないので、公衆 Wi-Fi などで通信を書き換えられると、偽のページへ誘導されることがあります(SSL ストリップ)。

HSTS を受け取ったブラウザは、max-age の期間中、リンクや手入力が http:// でも最初から https:// で接続します。危ない最初の http 通信そのものがなくなります。

自分で確認する方法

ターミナルで次のコマンドを実行します。1つ目で Strict-Transport-Security が表示され、2つ目で Location が https:// になっていれば設定できています。

HSTS が付いているか

curl -sI https://example.com | grep -i strict-transport-security

http から https へ転送されるか

curl -sI http://example.com | grep -i location

max-age・includeSubDomains・preload の決め方

max-age は半年(15552000秒)以上、一般的には2年(63072000秒)にします。includeSubDomains を付けると、すべてのサブドメインも HTTPS 必須になります。HTTPS に対応していないサブドメインがないか確認してから付けてください。

preload を付けて hstspreload.org に登録すると、初めて訪れる人にも最初から HTTPS が強制されます。ただし取り消しには時間がかかるので、すべてのサブドメインを HTTPS で運用し続けられる場合だけにしましょう。

直し方

httpからhttpsへの転送

http:// へのアクセスを https:// へ転送します。

Vercel・Netlify・Cloudflare Pages は自動で転送します。転送されない場合は、独自ドメインの DNS が別のサーバーを向いていないか確認してください。

nginx の場合

server {
  listen 80;
  server_name example.com;
  return 301 https://$host$request_uri;
}

HSTS(HTTPSの強制)

Strict-Transport-Security を付けると、ブラウザが次回から必ず https で接続します。

Next.js の場合

// next.config.mjs
const securityHeaders = [
  { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains' },
  { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
]

export default {
  async headers() {
    return [{ source: '/:path*', headers: securityHeaders }]
  },
}

Vercel で静的サイト・Vite などを公開している場合

// vercel.json(Next.js 以外を Vercel で公開している場合)
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains" },
        { "key": "X-Frame-Options", "value": "SAMEORIGIN" },
        { "key": "X-Content-Type-Options", "value": "nosniff" },
        { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
        { "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" }
      ]
    }
  ]
}

Netlify・Cloudflare Pages の場合

# public/_headers(Netlify・Cloudflare Pages)
/*
  Strict-Transport-Security: max-age=63072000; includeSubDomains
  X-Frame-Options: SAMEORIGIN
  X-Content-Type-Options: nosniff
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()

1つの設定で HSTS・クリックジャッキング・nosniff・Referrer-Policy・Permissions-Policy をまとめて直せます。カメラや位置情報を使うアプリは、Permissions-Policy の該当機能を self に変えてください。

よくある質問

HSTS を設定したあと、HTTP に戻せますか?
max-age=0 を返すと解除できます。ただし、すでに訪れたブラウザは、その応答を受け取るまで以前の max-age の期間 HTTPS を強制し続けます。
HSTSの設定方法|Next.js・Vercel・Netlifyでhttpsを強制する | IDEAVALU