fix(backend): Serve valid headers for HSTS and HSTS preload

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
This commit is contained in:
ゆめ 2024-10-19 02:31:41 -05:00
parent b1aac6acc3
commit 1d432c754e
No known key found for this signature in database
9 changed files with 69 additions and 5 deletions

View file

@ -174,6 +174,12 @@ id: 'aidx'
# Whether disable HSTS # Whether disable HSTS
#disableHsts: true #disableHsts: true
# Whether to enable HSTS preload
# Read these before enabling:
# - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security#preloading_strict_transport_security
# - https://hstspreload.org/
#hstsPreload: false
# Number of worker processes # Number of worker processes
#clusterLimit: 1 #clusterLimit: 1

View file

@ -168,6 +168,12 @@ id: 'aidx'
# Whether disable HSTS # Whether disable HSTS
#disableHsts: true #disableHsts: true
# Whether to enable HSTS preload
# Read these before enabling:
# - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security#preloading_strict_transport_security
# - https://hstspreload.org/
#hstsPreload: false
# Number of worker processes # Number of worker processes
#clusterLimit: 1 #clusterLimit: 1

View file

@ -250,6 +250,12 @@ id: 'aidx'
# Whether disable HSTS # Whether disable HSTS
#disableHsts: true #disableHsts: true
# Whether to enable HSTS preload
# Read these before enabling:
# - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security#preloading_strict_transport_security
# - https://hstspreload.org/
#hstsPreload: false
# Number of worker processes # Number of worker processes
#clusterLimit: 1 #clusterLimit: 1

View file

@ -161,6 +161,12 @@ id: 'aidx'
# Whether disable HSTS # Whether disable HSTS
#disableHsts: true #disableHsts: true
# Whether to enable HSTS preload
# Read these before enabling:
# - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security#preloading_strict_transport_security
# - https://hstspreload.org/
#hstsPreload: false
# Number of worker processes # Number of worker processes
#clusterLimit: 1 #clusterLimit: 1

View file

@ -182,6 +182,12 @@ id: "aidx"
# Whether disable HSTS # Whether disable HSTS
#disableHsts: true #disableHsts: true
# Whether to enable HSTS preload
# Read these before enabling:
# - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security#preloading_strict_transport_security
# - https://hstspreload.org/
#hstsPreload: false
# Number of worker processes # Number of worker processes
#clusterLimit: 1 #clusterLimit: 1

View file

@ -28,6 +28,7 @@ type Source = {
socket?: string; socket?: string;
chmodSocket?: string; chmodSocket?: string;
disableHsts?: boolean; disableHsts?: boolean;
hstsPreload?: boolean;
db: { db: {
host: string; host: string;
port: number; port: number;
@ -107,6 +108,7 @@ export type Config = {
socket: string | undefined; socket: string | undefined;
chmodSocket: string | undefined; chmodSocket: string | undefined;
disableHsts: boolean | undefined; disableHsts: boolean | undefined;
hstsPreload: boolean | undefined;
db: { db: {
host: string; host: string;
port: number; port: number;
@ -241,6 +243,7 @@ export function loadConfig(): Config {
socket: config.socket, socket: config.socket,
chmodSocket: config.chmodSocket, chmodSocket: config.chmodSocket,
disableHsts: config.disableHsts, disableHsts: config.disableHsts,
hstsPreload: config.hstsPreload ?? false,
host, host,
hostname, hostname,
scheme, scheme,

View file

@ -31,6 +31,7 @@ import { HealthServerService } from './HealthServerService.js';
import { ClientServerService } from './web/ClientServerService.js'; import { ClientServerService } from './web/ClientServerService.js';
import { OpenApiServerService } from './api/openapi/OpenApiServerService.js'; import { OpenApiServerService } from './api/openapi/OpenApiServerService.js';
import { OAuth2ProviderService } from './oauth/OAuth2ProviderService.js'; import { OAuth2ProviderService } from './oauth/OAuth2ProviderService.js';
import { makeHstsHook } from './hsts.js';
const _dirname = fileURLToPath(new URL('.', import.meta.url)); const _dirname = fileURLToPath(new URL('.', import.meta.url));
@ -81,12 +82,9 @@ export class ServerService implements OnApplicationShutdown {
this.#fastify = fastify; this.#fastify = fastify;
// HSTS // HSTS
// 6months (15552000sec)
if (this.config.url.startsWith('https') && !this.config.disableHsts) { if (this.config.url.startsWith('https') && !this.config.disableHsts) {
fastify.addHook('onRequest', (request, reply, done) => { const preload = this.config.hstsPreload;
reply.header('strict-transport-security', 'max-age=15552000; preload'); fastify.addHook('onRequest', makeHstsHook(preload));
done();
});
} }
// Register raw-body parser for ActivityPub HTTP signature validation. // Register raw-body parser for ActivityPub HTTP signature validation.

View file

@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { FastifyReply, FastifyRequest } from "fastify";
export function hstsHook(_request: FastifyRequest, reply: FastifyReply, done: () => void) {
reply.header('strict-transport-security', 'max-age=15552000');
done();
}
export function hstsPreloadHook(request: FastifyRequest, reply: FastifyReply, done: () => void) {
// we must permanent redirect http to https for preload to be eligible
if ((request.headers['x-forwarded-proto'] ?? request.protocol) === 'http') {
reply.redirect(`https://${request.hostname}${request.url}`, 301);
return;
}
// 1 year is mandatory for preload
reply.header('strict-transport-security', 'max-age=31536000; includeSubDomains; preload');
}
// 6months (15552000sec) by default, 1year (31536000sec) if preload is enabled
export function makeHstsHook(preload: boolean = false) {
return preload ? hstsPreloadHook : hstsHook;
}

View file

@ -52,6 +52,7 @@ import { FeedService } from './FeedService.js';
import { UrlPreviewService } from './UrlPreviewService.js'; import { UrlPreviewService } from './UrlPreviewService.js';
import { ClientLoggerService } from './ClientLoggerService.js'; import { ClientLoggerService } from './ClientLoggerService.js';
import type { FastifyInstance, FastifyPluginOptions, FastifyReply } from 'fastify'; import type { FastifyInstance, FastifyPluginOptions, FastifyReply } from 'fastify';
import { makeHstsHook } from '../hsts.js';
const _filename = fileURLToPath(import.meta.url); const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename); const _dirname = dirname(_filename);
@ -214,6 +215,12 @@ export class ClientServerService {
return; return;
} }
// HSTS
if (this.config.url.startsWith('https') && !this.config.disableHsts) {
const preload = this.config.hstsPreload;
fastify.addHook('onRequest', makeHstsHook(preload));
}
// %71ueueとかでリクエストされたら困るため // %71ueueとかでリクエストされたら困るため
const url = decodeURI(request.routeOptions.url); const url = decodeURI(request.routeOptions.url);
if (url === bullBoardPath || url.startsWith(bullBoardPath + '/')) { if (url === bullBoardPath || url.startsWith(bullBoardPath + '/')) {