Closed10
[Next.js] セキュリティ向上のために Security Headers を設定する
ピン留めされたアイテム
TL;DR
- Vercel にデプロイしない場合、デフォルトだと
Strict-Transport-Security
が追加されない (HTTPS を強制するやつ) -
next.config.js
で HTTP response header を一括で設定できる - 対応度合いの確認には Security Headers が便利
Next.js 製のサイト(SSR/SSG) の開発にあたって、HTTP resonse headers の設定を行ないました。
Advanced Features: Security Headers | Next.js
Security Headers .com
このサイトで Security Header の対応度合いをチェックできる。
Before
新規で Next.js プロジェクトを作成して何も設定せずに Amplify でデプロイ後 Security Headers.com でチェックした結果は F だった。
After
Security Headers を設定したら A になった🎉
作業内容
- ルート以下に
headers.js
を追加 -
next.config.js
でheaders()
の初期化を追加
headers.js
module.exports = [
{
key: 'X-DNS-Prefetch-Control',
value: 'on',
},
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
// todo: Server が決まってる場合は設定できる
// {
// key: 'Server',
// value: 'Apache', // phony server value
// },
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'X-Frame-Options',
value: 'sameorigin',
},
{
key: 'X-XSS-Protection',
value: '1; mode=block',
},
{
key: 'Referrer-Policy',
value: 'same-origin',
},
{
key: 'Permissions-Policy',
value: 'camera=*',
},
// todo: Content Security Policy を適用する
{
key: 'Content-Security-Policy',
value: 'default-src \'self\'',
},
];
以下は next.config.js
の例。
next.config.js
// 追加した `headers.js` を読み込む
const headers = require('./headers');
module.exports = _ => {
return {
reactStrictMode: true,
eslint: {
dirs: ['src']
},
async headers() {
return [
{
// 全てのパスに Security Headers を適用する
source: '/(.*)',
headers,
},
];
},
}
}
参考:
参考
Next.js 周り
-
Advanced Features: Security Headers | Next.js
- 今回行った設定
-
Quick security wins for your Next.js app
- 今回かなり参考にした記事
セキュリティ
-
Web Security Cheat Sheet
- MDN のセキュリティチートシート
Content Security Policy
- コンテンツセキュリティポリシー (CSP) | MDN
-
Content Security Policy でユーザーを守ろう
- CSP の説明。分かりやすかったです。
async headers() {
return [
{
// 全てのパスに Security Headers を適用する
source: '/(.*)',
headers,
},
];
},
このままですとルートパスで追加した設定が反映されないです。
全てのパスに適用するには、 source: '/:path*'
にする必要があります。
自分もハマったのでここに残しておきます。
参考
{
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level
// `/` or `/fr` routes like /:path* would
source: '/(.*)',
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
このスクラップは2021/10/08にクローズされました