[Support Guide]: How to apply Access Control for Netlify Functions?

Last checked by Netlify Support Team: November 2024

Introduction:

That is a great question, we do get it from time to time. But the answer is not that straightforward.

First, there are 2 ways someone might think this works:

Can I save my Function invocation count by restricting the function to be called only from my frontend?

The answer to that is no. Unfortunately, it just won’t work. No matter what you do, the moment you deploy a Netlify Function, its endpoint is accessible to everyone and it can be subjected to abuse. Sorry to say but there’s absolutely no way to protect your function invocation count yet. The reasons for this will be discussed further in this post. However, the good part is, we haven’t seen a lot of users whose functions were abused in a way that cost them any money, so this isn’t a frequent problem in practice. Which brings us to the second question which we can help with:

Can I make sure only my site is able to receive a response from my function?

Technically, yes, it’s possible. But it’s a lot more complicated than that to implement. The primary reason for that is, browsers make it really easy to see network requests that are being made by a web app. Furthermore, there are options to easily copy the requests as cURL and thus, that makes it more difficult for developers to make the endpoints secure. Here’s why:

Since the endpoints can be accessed by anyone, you need to determine a way to distinguish your application from the rest of the requests. How can you do that? Here are a few approaches:

Approach 1: Using default request Headers

You could try to use request headers that a browser generally automatically sends along with the requests like the referer HTTP request header for example. In the serverless function, you could implement something like:

if (event.headers.referer.includes('mydomain.com')) {
 // process the function
} else {
  return {
    statusCode: 401,
    body: JSON.stringify('Unauthorized')
  }
}

The upside is, it’s really easy to implement this. The downside is, it’s a very primitive layer of security. It won’t take a lot of guesses for someone to try and spoof the referer header of their request to get successful in getting a response.

You could also add multiple checks for example, you could check for referer, origin, host and multiple such headers to determine whether to return a response or not.

This would definitely be stronger than a single check, but again, someone can simply try all the headers in the developer tools and then would eventually be successful.

Approach 2: Using custom request headers or body

You could also send a custom header or a payload with each request and check for that inside your function. For example, in your frontend, you could do:

fetch('url', {
  headers: {
    security: 12345
  }
})

In your serverless function:

if (event.headers?.security === 12345) {
  // process the function
} else {
  return {
    statusCode: 401,
    body: JSON.stringify('Unauthorized')
  }
}

So, this one could be a little more secure than others, in the sense, it won’t be ‘guessable’. A person might try to use the common headers explained previously and would be unsuccessful, but as already pointed many times, they could see a pattern of you trying to use this header multiple times and thus, they could guess it eventually.

You could try to spice things up by randomly generating this header value with a specific logic for example, using Date.now() to get the timestamp and multiplying it with some random number or something like that. Considering you’ve set a logic in your serverless function to decode this ‘secret key’, it still won’t work because your serverless function would run on a different timezone than the client device which would make the time-based verifications difficult.

Furthermore, all of these approaches are even easier to breach for users who know their way around the command line. All it would take is something like copy as cURL and paste it and get a response as it would contain the exact ‘secret’ data that you used to make a request.

Approach 3: Using Netlify Edge Functions

You can use Netlify Edge Functions to protect your Functions as well. Considering they’re cheaper than Functions, that could be a viable choice. You can add the Edge Functions for /.netlify/functions/* path (or for a specific function), and within that Edge Function, check if the request should pass to your function or not. This would ramp up your Edge Function invocation count, while keeping your Functions invocation count in check.

Conclusion:

So here we’ve covered some ways using which you can add some layers of security to your Functions endpoint. None of them assure you a 100% security, but it’ll just make if difficult for a malicious user to breach some levels of security to extract data out of your endpoint. All in all, you should consider your comfort, the budget and time constraints of your project among other things to decide what way would be best for you.

Also, if you’ve any more ways to protect your endpoints, please share them with the forums.

5 Likes

It is the Referer header (single r) which is in fact a misspelling.

The Referrer-Policy header (with two r’s) can of course remove the Referer header.

Thank you. I have updated the spellings.