Step-by-Step Guide
7 steps

How to Secure Your Netlify App

Netlify provides hosting, serverless functions, and edge computing. While the platform handles infrastructure security, you need to configure security headers, protect your functions, and manage environment variables properly. This guide covers all the essentials.

Find security issues automatically before attackers do.

Follow These Steps

1

Add security headers with _headers file

Create a _headers file in your publish directory to add security headers to all responses.

Code Example
# _headers (in your publish directory)
/*
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  X-XSS-Protection: 0
  Referrer-Policy: strict-origin-when-cross-origin
  Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
  Permissions-Policy: camera=(), microphone=(), geolocation=()
  Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https:; frame-ancestors 'none'

You can also configure headers in netlify.toml. The _headers file takes precedence over netlify.toml for the same paths.

2

Configure environment variables securely

Use Netlify environment variables for all secrets. Set different values for production and deploy previews.

Code Example
# In Netlify Dashboard > Site settings > Environment variables
# Set scope for each variable:
# - Production: Real API keys
# - Deploy previews: Test/sandbox keys
# - Branch deploys: Test/sandbox keys

# In netlify.toml, reference them:
[build.environment]
  NODE_ENV = "production"
  # Never put secrets in netlify.toml - use the dashboard

Mark sensitive environment variables as "Secret" in the Netlify dashboard. This prevents them from appearing in build logs.

3

Secure Netlify Functions

Add authentication and input validation to every Netlify Function that handles sensitive operations.

Code Example
// netlify/functions/create-order.ts
import { Handler } from '@netlify/functions'
import { z } from 'zod'

const OrderSchema = z.object({
  productId: z.string().min(1),
  quantity: z.number().int().min(1).max(99)
})

export const handler: Handler = async (event) => {
  // Check auth
  const token = event.headers.authorization?.replace('Bearer ', '')
  if (!token) {
    return { statusCode: 401, body: JSON.stringify({ error: 'Unauthorized' }) }
  }
  // Validate input
  const parsed = OrderSchema.safeParse(JSON.parse(event.body || '{}'))
  if (!parsed.success) {
    return { statusCode: 400, body: JSON.stringify({ error: 'Invalid input' }) }
  }
  // Process order
  return { statusCode: 200, body: JSON.stringify({ success: true }) }
}
4

Protect deploy previews

Deploy previews are public by default. Use Netlify password protection or branch-specific access controls to restrict access.

Code Example
# netlify.toml
[context.deploy-preview]
  # Use different environment for previews
  [context.deploy-preview.environment]
    STRIPE_KEY = "sk_test_..."
    DATABASE_URL = "postgresql://test-db/..."
5

Configure redirect rules securely

Set up proper redirects to enforce HTTPS and prevent open redirects.

Code Example
# _redirects file
# Force HTTPS
http://yourdomain.com/* https://yourdomain.com/:splat 301!

# Proxy API calls through Netlify (hides backend URL)
/api/*  https://your-backend.com/api/:splat  200

# SPA fallback (must be last)
/*  /index.html  200
6

Add rate limiting with Netlify Edge Functions

Use Edge Functions to rate limit requests before they hit your serverless functions.

Code Example
// netlify/edge-functions/rate-limit.ts
import { Context } from 'https://edge.netlify.com'

const WINDOW_MS = 60000
const MAX_REQUESTS = 60
const requests = new Map<string, { count: number; resetAt: number }>()

export default async (request: Request, context: Context) => {
  const ip = context.ip
  const now = Date.now()
  const record = requests.get(ip)
  
  if (record && record.resetAt > now) {
    if (record.count >= MAX_REQUESTS) {
      return new Response('Too Many Requests', { status: 429 })
    }
    record.count++
  } else {
    requests.set(ip, { count: 1, resetAt: now + WINDOW_MS })
  }
  
  return context.next()
}
7

Scan your Netlify deployment

Run a VAS scan on your Netlify site URL to verify security headers, function protection, and overall security posture.

Check both your production domain and any deploy preview URLs.

What You'll Achieve

Your Netlify app now has security headers on all pages, protected environment variables, secured serverless functions, rate limiting, and deploy previews locked down. Your site is hardened against common web attacks.

Common Mistakes to Avoid

Mistake

Putting secrets in netlify.toml

Fix

netlify.toml is committed to git and visible to anyone with repo access. Always use the Netlify dashboard for secrets.

Mistake

Not setting the _headers file in the correct directory

Fix

The _headers file must be in your publish directory (usually build/ or dist/). If it is in the project root, it will not be deployed.

Mistake

Using the same API keys for deploy previews and production

Fix

Set different environment variable values for each deploy context. Use test/sandbox keys for previews to prevent accidental production data access.

Frequently Asked Questions

Does Netlify provide security headers by default?

Netlify provides HTTPS automatically but does not add application security headers. You must configure headers via a _headers file or netlify.toml.

Are Netlify Functions secure by default?

Netlify Functions are publicly accessible endpoints. You must add your own authentication and input validation. They have a default timeout and memory limit which provides some protection against abuse.

How do I hide my backend URL when using Netlify?

Use Netlify redirects to proxy API calls. Set up a redirect rule like /api/* -> https://your-backend.com/:splat with status 200. This hides the backend URL from the browser.

Ready to Secure Your App?

VAS automatically scans your deployed app for the security issues covered in this guide. Get actionable results in minutes.

Start Security Scan