1

It is recommended to do this often in web apps:

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

// Define allowed origins
const allowedOrigins = [
  'http://localhost:3000',
  'http://localhost:3001',
  'http://localhost:3002',
  'http://localhost:3003',
  'https://my.site',
]

export function middleware(request: NextRequest) {
  // Get the origin from the request headers
  const origin = request.headers.get('origin')

  // If the origin is not in the allowed list, return null in the header
  const corsOrigin =
    origin && allowedOrigins.includes(origin)
      ? origin
      : allowedOrigins[0]

  // Handle OPTIONS preflight request
  if (request.method === 'OPTIONS') {
    return NextResponse.json(
      {},
      {
        headers: {
          'Access-Control-Allow-Origin': corsOrigin,
          'Access-Control-Allow-Methods':
            'GET, POST, PUT, DELETE, OPTIONS',
          'Access-Control-Allow-Headers': 'Content-Type, Authorization',
          'Access-Control-Max-Age': '86400',
        },
      },
    )
  }

  // Handle the actual request
  const response = NextResponse.next()

  // Add CORS headers to the response
  response.headers.set('Access-Control-Allow-Origin', corsOrigin)
  response.headers.set(
    'Access-Control-Allow-Methods',
    'GET, POST, PUT, DELETE, OPTIONS',
  )
  response.headers.set(
    'Access-Control-Allow-Headers',
    'Content-Type, Authorization',
  )

  return response
}

// Configure which routes use this middleware
export const config = {
  matcher: '/:path*',
}

Here, this is Next.js middleware which checks if you are on localhost, and allows any request to be made.

Isn't that very insecure? Or at least, a hacker could crawl your website and make API calls if they load it in Puppeteer or something and make HTTP/REST requests from "localhost". Puppeteer is a browser API in Node.js for web automation.

So if I were a hacker, I would create a web app, load it in localhost, and make a request from the frontend localhost to whatever backend API I want. Perhaps there is a simpler way to hack along these lines, but yeah.

How can I allow CORS for localhost (so I can test against a production API server), but only for me, not anyone else?

4
  • yes, it's insecure. (but people are supposed to know that and remove the headers before going live, or use if environment = development for setting them) Don't set CORS headers and keep everything same-site/domain. (unless it's necessary and then only for specific origins) To debug when localhost runs front and back end on separate ports use a proxy which makes front and back end same port. If you are testing a live server, everything will be same-site/domain anyway, so you don't need CORS headers. Commented Nov 5, 2024 at 20:04
  • you'll also find a variant of this where it just dynamically creates the CORS allowed origin according to the origin header. (even worse...) It should be noted, though, that it would be difficult to craft a CSRF attack that runs in localhost origin. Remember the attacker is trying to make a request on behalf of someone else. Commented Nov 5, 2024 at 20:14
  • for debugging you can also just use a profile with the browser's CORS rules turned off. (but be sure not to visit any other sites while running under that profile) Commented Nov 5, 2024 at 20:23
  • See also What are the security risk of enabling cors on localhost?, localhost as allowed origin in production. Commented Nov 18, 2024 at 15:43

1 Answer 1

1

I would create a web app, load it in localhost, and make a request from the frontend localhost to whatever backend API I want.

An attacker can already perform any request they want, using cURL or Python or anything that can perform HTTP requests. The only thing that CORS allows is certain types of cross-domain requests in the browser. If the attacker uses something else than a browser, they can still perform any type of request.

CORS is especially dangerous when the site uses cookie authentication and specifies a Access-Control-Allow-Credentials header. This makes it possible for other sites to perform requests and also include the authentication cookie in the request.

However, since you have:

'Access-Control-Allow-Headers': 'Content-Type, Authorization'

I suspect that your service uses an Authorization header for authentication. In that case, if an attacker sends a request from another site, they cannot use the user's authentication token. A request is unauthenticated unless the attacker includes a token of their own.

const allowedOrigins = ['http://localhost:3000',

This could provide some risk if a victim is running another vulnerable app at this location, and the attacker can use that to perform some request to your app which would not be otherwise possible. This seems an unlikely scenario from your example.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.