Secure Headers ミドルウェア
Secure Headers ミドルウェアは、セキュリティヘッダーの設定を簡単にします。Helmet の機能から一部着想を得ており、特定のセキュリティヘッダーの有効化と無効化を制御できます。
インポート
ts
import { Hono } from 'hono'
import { secureHeaders } from 'hono/secure-headers'使い方
デフォルトで適切な設定を使用できます。
ts
const app = new Hono()
app.use(secureHeaders())不要なヘッダーを false に設定すると、送信を抑制できます。
ts
const app = new Hono()
app.use(
'*',
secureHeaders({
xFrameOptions: false,
xXssProtection: false,
})
)文字列でヘッダーのデフォルト値を上書きできます。
ts
const app = new Hono()
app.use(
'*',
secureHeaders({
strictTransportSecurity:
'max-age=63072000; includeSubDomains; preload',
xFrameOptions: 'DENY',
xXssProtection: '1',
})
)サポートするオプション
各オプションは、次のヘッダーのキーと値に対応します。
ミドルウェアの競合
同じヘッダーを操作するミドルウェアを使う場合、指定する順番に注意してください。
この例では、Secure-headers が作用し、x-powered-by を削除します。
ts
const app = new Hono()
app.use(secureHeaders())
app.use(poweredBy())この例では、Powered-By が作用し、x-powered-by を追加します。
ts
const app = new Hono()
app.use(poweredBy())
app.use(secureHeaders())Content-Security-Policy の設定
ts
const app = new Hono()
app.use(
'/test',
secureHeaders({
reportingEndpoints: [
{
name: 'endpoint-1',
url: 'https://example.com/reports',
},
],
// -- or alternatively
// reportTo: [
// {
// group: 'endpoint-1',
// max_age: 10886400,
// endpoints: [{ url: 'https://example.com/reports' }],
// },
// ],
contentSecurityPolicy: {
defaultSrc: ["'self'"],
baseUri: ["'self'"],
childSrc: ["'self'"],
connectSrc: ["'self'"],
fontSrc: ["'self'", 'https:', 'data:'],
formAction: ["'self'"],
frameAncestors: ["'self'"],
frameSrc: ["'self'"],
imgSrc: ["'self'", 'data:'],
manifestSrc: ["'self'"],
mediaSrc: ["'self'"],
objectSrc: ["'none'"],
reportTo: 'endpoint-1',
reportUri: '/csp-report',
sandbox: ['allow-same-origin', 'allow-scripts'],
scriptSrc: ["'self'"],
scriptSrcAttr: ["'none'"],
scriptSrcElem: ["'self'"],
styleSrc: ["'self'", 'https:', "'unsafe-inline'"],
styleSrcAttr: ['none'],
styleSrcElem: ["'self'", 'https:', "'unsafe-inline'"],
upgradeInsecureRequests: [],
workerSrc: ["'self'"],
},
})
)nonce 属性
hono/secure-headers からインポートした NONCE を scriptSrc または styleSrc に追加すると、script または style 要素に nonce 属性を追加できます。
tsx
import { secureHeaders, NONCE } from 'hono/secure-headers'
import type { SecureHeadersVariables } from 'hono/secure-headers'
// Specify the variable types to infer the `c.get('secureHeadersNonce')`:
type Variables = SecureHeadersVariables
const app = new Hono<{ Variables: Variables }>()
// Set the pre-defined nonce value to `scriptSrc`:
app.get(
'*',
secureHeaders({
contentSecurityPolicy: {
scriptSrc: [NONCE, 'https://allowed1.example.com'],
},
})
)
// Get the value from `c.get('secureHeadersNonce')`:
app.get('/', (c) => {
return c.html(
<html>
<body>
{/** contents */}
<script
src='/js/client.js'
nonce={c.get('secureHeadersNonce')}
/>
</body>
</html>
)
})nonce 値を自分で生成するには、次のように関数を指定することもできます。
tsx
const app = new Hono<{
Variables: { myNonce: string }
}>()
const myNonceGenerator: ContentSecurityPolicyOptionHandler = (c) => {
// This function is called on every request.
const nonce = Math.random().toString(36).slice(2)
c.set('myNonce', nonce)
return `'nonce-${nonce}'`
}
app.get(
'*',
secureHeaders({
contentSecurityPolicy: {
scriptSrc: [myNonceGenerator, 'https://allowed1.example.com'],
},
})
)
app.get('/', (c) => {
return c.html(
<html>
<body>
{/** contents */}
<script src='/js/client.js' nonce={c.get('myNonce')} />
</body>
</html>
)
})Permission-Policy の設定
Permission-Policy ヘッダーは、ブラウザーで使える機能や API を制御します。設定例は次のとおりです。
ts
const app = new Hono()
app.use(
'*',
secureHeaders({
permissionsPolicy: {
fullscreen: ['self'], // fullscreen=(self)
bluetooth: ['none'], // bluetooth=(none)
payment: ['self', 'https://example.com'], // payment=(self "https://example.com")
syncXhr: [], // sync-xhr=()
camera: false, // camera=none
microphone: true, // microphone=*
geolocation: ['*'], // geolocation=*
usb: ['self', 'https://a.example.com', 'https://b.example.com'], // usb=(self "https://a.example.com" "https://b.example.com")
accelerometer: ['https://*.example.com'], // accelerometer=("https://*.example.com")
gyroscope: ['src'], // gyroscope=(src)
magnetometer: [
'https://a.example.com',
'https://b.example.com',
], // magnetometer=("https://a.example.com" "https://b.example.com")
},
})
)