feat: add csrf support to api & web components (#999)

This commit is contained in:
Pujit Mehrotra
2025-01-08 14:22:06 -05:00
committed by GitHub
parent 4404208deb
commit f0f5a3057a
7 changed files with 29 additions and 3 deletions

View File

@@ -4,6 +4,7 @@ import { AuthZService } from 'nest-authz';
import type { UserAccount } from '@app/graphql/generated/api/types';
import { Role } from '@app/graphql/generated/api/types';
import { getters } from '@app/store';
import { handleAuthError } from '@app/utils';
import { ApiKeyService } from './api-key.service';
@@ -205,6 +206,10 @@ export class AuthService {
}
}
public validateCsrfToken(token?: string): boolean {
return Boolean(token) && token === getters.emhttp().var.csrfToken;
}
/**
* Returns a user object representing a session.
* Note: Does NOT perform validation.

View File

@@ -18,6 +18,9 @@ export class UserCookieStrategy extends PassportStrategy(Strategy, strategyName)
}
public validate = async (req: CustomRequest): Promise<any> => {
return this.authService.validateCookiesCasbin(req.cookies);
return (
this.authService.validateCsrfToken(req.headers['x-csrf-token']) &&
this.authService.validateCookiesCasbin(req.cookies)
);
};
}

View File

@@ -1,3 +1,5 @@
import type { FastifyRequest } from '@app/types/fastify';
export interface CustomRequest extends FastifyRequest {}
export interface CustomRequest extends FastifyRequest {
headers: FastifyRequest['headers'] & { 'x-csrf-token'?: string };
}

View File

@@ -10,5 +10,7 @@ VITE_ALLOW_CONSOLE_LOGS=true
# For an Unraid Webgui deployment, set this to 10.
VITE_TAILWIND_BASE_FONT_SIZE=16
VITE_WEBGUI=http://localhost:3001
# static override for csrf token during development.
VITE_CSRF_TOKEN="0000000000000000"
# Flag for mocking a user session during development via an unsecure cookie
VITE_MOCK_USER_SESSION=true

View File

@@ -20,7 +20,9 @@ const httpEndpoint = WEBGUI_GRAPHQL;
const wsEndpoint = new URL(WEBGUI_GRAPHQL.toString().replace('http', 'ws'));
// const headers = { 'x-api-key': serverStore.apiKey };
const headers = {};
const headers = {
'x-csrf-token': globalThis.csrf_token,
};
const httpLink = createHttpLink({
uri: httpEndpoint.toString(),

7
web/helpers/globals.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
declare global {
// eslint-disable-next-line no-var
var csrf_token: string;
}
// an export or import statement is required to make this file a module
export {};

View File

@@ -40,6 +40,11 @@ const DOCS_REGISTRATION_REPLACE_KEY = new URL('/go/changing-the-flash-device/',
const SUPPORT = new URL('https://unraid.net');
// initialize csrf_token in nuxt playground
if (import.meta.env.VITE_CSRF_TOKEN) {
globalThis.csrf_token = import.meta.env.VITE_CSRF_TOKEN;
}
export {
ACCOUNT,
ACCOUNT_CALLBACK,