add security headers and CORS

This commit is contained in:
rubikscraft 2022-03-31 22:40:11 +02:00
parent 1223bcbb19
commit 36e9789070
No known key found for this signature in database
GPG key ID: 1463EBE9200A5CD4
6 changed files with 80 additions and 7 deletions

View file

@ -31,6 +31,7 @@
"bcrypt": "^5.0.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"fastify-helmet": "^7.0.1",
"fastify-multipart": "^5.3.1",
"fastify-static": "^4.6.1",
"file-type": "^17.1.1",

View file

@ -4,6 +4,7 @@ import {
FastifyAdapter,
NestFastifyApplication
} from '@nestjs/platform-fastify';
import fastifyHelmet from 'fastify-helmet';
import * as multipart from 'fastify-multipart';
import { ValidateOptions } from 'picsur-shared/dist/util/validate';
import { AppModule } from './app.module';
@ -13,12 +14,14 @@ import { MainExceptionFilter } from './layers/httpexception/httpexception.filter
import { SuccessInterceptor } from './layers/success/success.interceptor';
import { PicsurLoggerService } from './logger/logger.service';
import { MainAuthGuard } from './managers/auth/guards/main.guard';
import { HelmetOptions } from './security';
async function bootstrap() {
// Create fasify
const fastifyAdapter = new FastifyAdapter();
// TODO: generic error messages
fastifyAdapter.register(multipart as any);
await fastifyAdapter.register(multipart as any);
await fastifyAdapter.register(fastifyHelmet, HelmetOptions);
// Create nest app
const app = await NestFactory.create<NestFastifyApplication>(
@ -28,16 +31,16 @@ async function bootstrap() {
bufferLogs: true,
},
);
// app.enableCors({
// origin: 'self'
// });
// Configure nest app
app.useGlobalFilters(new MainExceptionFilter());
app.useGlobalInterceptors(new SuccessInterceptor());
app.useGlobalPipes(new ValidationPipe(ValidateOptions));
app.useGlobalGuards(
new MainAuthGuard(
app.get(Reflector),
app.get(UsersService),
),
new MainAuthGuard(app.get(Reflector), app.get(UsersService)),
);
// Configure logger

View file

@ -17,6 +17,7 @@ import { Permission } from '../../models/dto/permissions.dto';
import { ImageUploadDto } from '../../models/requests/imageroute.dto';
import { ImageIdValidator } from './imageid.validator';
// This is the only controller with CORS enabled
@Controller('i')
@RequiredPermissions(Permission.ImageView)
export class ImageController {

View file

@ -1,12 +1,22 @@
import { Module } from '@nestjs/common';
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import cors from 'cors';
import { DecoratorsModule } from '../../decorators/decorators.module';
import { ImageManagerModule } from '../../managers/imagemanager/imagemanager.module';
import { ImageIdValidator } from './imageid.validator';
import { ImageController } from './imageroute.controller';
const corsConfig = cors({
// 48 hours
maxAge: 1728000,
});
@Module({
imports: [ImageManagerModule, DecoratorsModule],
providers: [ImageIdValidator],
controllers: [ImageController],
})
export class ImageModule {}
export class ImageModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(corsConfig).forRoutes('/i');
}
}

45
backend/src/security.ts Normal file
View file

@ -0,0 +1,45 @@
import { FastifyHelmetOptions } from 'fastify-helmet';
export const HelmetOptions: FastifyHelmetOptions = {
contentSecurityPolicy: {
directives: {
'default-src': ["'self'"],
'base-uri': ["'self'"],
'block-all-mixed-content': [],
'form-action': ["'self'"],
'frame-ancestors': ["'self'"],
'img-src': ["'self'", 'data:', 'blob:'],
'object-src': ["'none'"],
'script-src': ["'self'"],
'style-src': ["'self'", "'unsafe-inline'"],
'upgrade-insecure-requests': [],
},
useDefaults: false,
reportOnly: false,
},
// Require any external content to have CORS set
crossOriginEmbedderPolicy: true,
// Destroy reference to global object on new page
crossOriginOpenerPolicy: true,
crossOriginResourcePolicy: true,
// Dont fully understand the purpose of this
// But pretty sure we dont need it
expectCt: false,
// Do not send referrer header
referrerPolicy: true,
// Ensure browser doesnt connect with HTTP
hsts: true,
noSniff: true,
originAgentCluster: true,
// Prevent prefetching of dns
dnsPrefetchControl: true,
// We aint targeting IE, but it cant hurt
ieNoOpen: true,
// Only allow in iframe of same origin
frameguard: true,
permittedCrossDomainPolicies: true,
hidePoweredBy: true,
// Requires nonce for every stylesheet, this is too much work so we disable it
enableCSPNonces: false,
xssFilter: true,
};

View file

@ -4029,6 +4029,14 @@ fastify-formbody@5.2.0:
dependencies:
fastify-plugin "^3.0.0"
fastify-helmet@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fastify-helmet/-/fastify-helmet-7.0.1.tgz#506c288dc5a5bea4d7332c1b5aed8f69a3fe383b"
integrity sha512-/PSKDJZkBhJ0ioY1swOUfYNYQRfRnXD5X2eKD9TSVBuPKbH+OYg/IYBxad33uaOGlWn28MNOd+kw5sQKSWY1yA==
dependencies:
fastify-plugin "^3.0.0"
helmet "^5.0.1"
fastify-multipart@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/fastify-multipart/-/fastify-multipart-5.3.1.tgz#05254d8aa43dc02af6ce01f4e513a6c30bea2886"
@ -4462,6 +4470,11 @@ hdr-histogram-percentiles-obj@^3.0.0:
resolved "https://registry.yarnpkg.com/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz#9409f4de0c2dda78e61de2d9d78b1e9f3cba283c"
integrity sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==
helmet@^5.0.1:
version "5.0.2"
resolved "https://registry.yarnpkg.com/helmet/-/helmet-5.0.2.tgz#3264ec6bab96c82deaf65e3403c369424cb2366c"
integrity sha512-QWlwUZZ8BtlvwYVTSDTBChGf8EOcQ2LkGMnQJxSzD1mUu8CCjXJZq/BXP8eWw4kikRnzlhtYo3lCk0ucmYA3Vg==
hexoid@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18"