kubetail-org / edge-csrf

CSRF protection library for JavaScript that runs on the edge runtime (with Next.js, SvelteKit, Express, Node-HTTP integrations)
MIT License
140 stars 7 forks source link

Is there any way to protect only a specific path? #11

Open patrickn2 opened 1 year ago

patrickn2 commented 1 year ago

I would like to protect only my /api/ path, this means that I want to protect the GET method also If I don't ignore the GET method, the csrf token will not be created and inserted in the header of a normal page.

How to work around this?

amorey commented 1 year ago

You can selectively enable edge-csrf only for certain routes in the middleware file:

// middleware.ts

import csrf from 'edge-csrf';
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

// initalize protection function
const csrfProtect = csrf({
  cookie: {
    secure: process.env.NODE_ENV === 'production',
  },
});

export async function middleware(request: NextRequest) {
  const response = NextResponse.next();

  if request.url.startsWith('/api/') {
    // csrf protection
    const csrfError = await csrfProtect(request, response);

    // check result
    if (csrfError) {
      return new NextResponse('invalid csrf token', { status: 403 });
    }
  }

  return response;
}

This solution is url based so it will run both GET and POST requests through the edge-csrf middleware.

patrickn2 commented 1 year ago

The problem with this code is that I need to protect my GET api routes and if you execute this code, the other pages will not create the csrfToken to pass to my api route.

The method csrfProtect needs to be executed all times

amorey commented 1 year ago

You might be able to hack together a solution with edge-csrf but this library is designed to generate CSRF tokens on GET's and validate them on POST's so it doesn't sound like it will work for you. Are you sure there isn't a way to use POST handlers on your API routes?

patrickn2 commented 1 year ago

These API routes are only to get some data, so I don't think using POST is a good idea. If the owner could not give me a solution I will try to find another package :(

amorey commented 1 year ago

OWASP guidance is to consider GET, HEAD, and OPTIONS as safe methods that do not need to be appended with a CSRF token and POST, PUT, PATCH, and DELETE methods, as state changing verbs that should have a CSRF token attached to the request. If you're using javascript you can use fetch() to send data via POST easily.

patrickn2 commented 1 year ago

My ideia is to make it harder to crawlers/bots fetch my data, I know that this will not make it impossible to fetch the data but I want to make it harder adding a csrf validation.

devrenzz commented 7 months ago

You can selectively enable edge-csrf only for certain routes in the middleware file:

// middleware.ts

import csrf from 'edge-csrf';
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

// initalize protection function
const csrfProtect = csrf({
  cookie: {
    secure: process.env.NODE_ENV === 'production',
  },
});

export async function middleware(request: NextRequest) {
  const response = NextResponse.next();

  if request.url.startsWith('/api/') {
    // csrf protection
    const csrfError = await csrfProtect(request, response);

    // check result
    if (csrfError) {
      return new NextResponse('invalid csrf token', { status: 403 });
    }
  }

  return response;
}

This solution is url based so it will run both GET and POST requests through the edge-csrf middleware.

Hello, do this also apply if I only need to have the edge-csrf enabled on api routes. I have supabase and I don't need the csrf but only on the api routes alone.

amorey commented 7 months ago

Hello, do this also apply if I only need to have the edge-csrf enabled on api routes. I have supabase and I don't need the csrf but only on the api routes alone.

If you only want to apply it to API routes then you can use the same strategy but looking the code again I would suggest doing this instead in order for the cookie to get set on non-api GET requests:

export async function middleware(request: NextRequest) {
  const response = NextResponse.next();

  // csrf protection
  const csrfError = await csrfProtect(request, response);

  // check result
  if (csrfError && request.url.startsWith('/api/')) {
    return new NextResponse('invalid csrf token', { status: 403 });
  }

  return response;
}