РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
⊗jsnsSpPtCf 184 of 201 menu
◀ ▶

Защита от подделки запроса в Nest

Браузер сам прикладывает куки к запросу на ваш API, если их выдал тот же сайт или злоумышленник подставил форму на чужой странице. Сервер не отличит добровольное действие пользователя от навязанного обращения без дополнительной метки.

Подделка запроса (Cross-Site Request Forgery, межсайтовая подделка запроса) снимается парой значений: секрет кладут в куку, а клиент при изменении данных присылает тот же секрет отдельным полем запроса. Готовый пакет csurf не подключаем, токен выпускаем сами в слое и проверяем в защитнике.

Покажем на примере постов:

npm install cookie-parser

Разбор кук включим в точке входа:

import { NestFactory } from '@nestjs/core'; import cookieParser from 'cookie-parser'; import { AppModule } from './app.module.js'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.use(cookieParser()); await app.listen(process.env.PORT ?? 3000); } await bootstrap();

Слой на безопасных методах создаёт токен, пишет его в куку и дублирует в ответе:

import { randomBytes } from 'node:crypto'; import { NextFunction, Request, Response } from 'express'; export function postCsrf( req: Request, res: Response, next: NextFunction, ) { if (req.method === 'GET' || req.method === 'HEAD') { const token = randomBytes(16).toString('hex'); res.cookie('csrf', token, { httpOnly: true, sameSite: 'strict', }); res.setHeader('X-CSRF-Token', token); } next(); }

Защитник сравнивает значение из куки и из запроса на изменяющих методах:

import { CanActivate, ExecutionContext, ForbiddenException, Injectable, } from '@nestjs/common'; import { Request } from 'express'; @Injectable() export class PostCsrfGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const req = context.switchToHttp().getRequest<Request>(); const cookie = req.cookies?.csrf; const header = req.headers['x-csrf-token']; if (typeof header !== 'string' || header !== cookie) { throw new ForbiddenException(); } return true; } }

Контроллер читает список без проверки, а запись данных вешает защитник:

import { Body, Controller, Get, Post, UseGuards, } from '@nestjs/common'; import { PostCsrfGuard } from './post.csrf.guard.js'; @Controller('posts') export class PostController { @Get() getPosts(): string { return 'All posts'; } @Post() @UseGuards(PostCsrfGuard) createPost(@Body() body: { title: string }): string { return body.title; } }

Модуль подключает слой ко всем адресам и регистрирует защитник:

import { MiddlewareConsumer, Module, NestModule, } from '@nestjs/common'; import { PostController } from './post.controller.js'; import { PostCsrfGuard } from './post.csrf.guard.js'; import { postCsrf } from './post.csrf.js'; @Module({ controllers: [PostController], providers: [PostCsrfGuard], }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(postCsrf).forRoutes(PostController); } }

Выпускайте свой токен в слое для WorkerController, сверяйте его в WorkerCsrfGuard на записи данных работников и подключите слой с защитником в WorkersModule.

← →
↑
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить