Back to blog

Follow and Subscribe

Enhancing Security Capabilities with VCL

Annie Srivastava

Security Technical Account Manager

Juan Carlos Murillo

Security Technical Account Manager

At the core of Fastly is Varnish, an open-source web accelerator that’s designed for high-performance content delivery. Varnish is the key to being able to accelerate dynamic content, APIs, and logic at the edge.

What is Fastly VCL?

Fastly VCL is a domain-specific programming language that has evolved from the Varnish proxy cache, which is part of Fastly's platform architecture. It's intentionally limited in range, which allows us to run it extremely fast, make it available to all requests that pass through Fastly, and maintain the security of the Fastly network. With Fastly VCL, you can do anything from adding a cookie or setting a Cache-Control header to implementing a complete paywall solution.

Fastly VCL can also be leveraged by our Next-Gen WAF (NGWAF) customers, for example, you may consider modifying HTTP headers in an HTTP request before it reaches your backend using NGWAF in line with the request flow. You can also modify HTTP headers on an HTTP response before the response is returned to the client.

In this post, we’ll review important VCL concepts and capabilities that are especially important from a security standpoint, along with examples showcasing how these features can be implemented. Initially, it is crucial to grasp, at a high level, the typical setup of the NGWAF Edge deployment within Fastly’s architecture, which you can see below in the flowchart.

VCL Use Cases

Below are some basic VCL examples to introduce you to the code structure and demonstrate its usefulness and simplicity. Please note that the snippets used in the examples can be applied to other subroutines and are not limited to the ones used in the examples.

Apply Rate Limiting

Edge Rate Limiting, a type of rate limiting implemented as a VCL service, helps you control the rate of requests sent to your Fastly services and origin servers from individual clients or clients forming a single identifiable group. Rate counters allow you to count requests by individual clients and penalty boxes allow you to penalize clients for exceeding rate limits you set.

The two main use cases for rate limiting are:

  1. To prevent abusive use of a website or service (e.g. by a scraping bot or a denial of service attack)

  2. To apply a limit on the use of a billable resource (e.g. to allow up to 1000 requests an hour to an API).

The example below will check if the user (identified by IP address) has exceeded 100 requests per second over the last 10 seconds and, if so, penalize them for 15 minutes. The check_rate() function is used to determine if a given client has exceeded a specified request rate. Review its parameters here.

penaltybox pb { }
ratecounter rc { }

sub vcl_recv {
  if (fastly.ff.visits_this_service == 0 && ratelimit.check_rate(client.ip, rc, 1, 10, 100, pb, 15m)) {
    error 429 "Too many requests";
  }
}

It is important to differentiate Edge Rate Limiting, the type of rate limiting explained in this example, and Advanced Rate Limiting, which is the type of rate limiting configured only through the NGWAF.

The Edge Rate Limiting product must be enabled on your account in order to use the rate-limiting primitives in VCL.

Modify HTTP requests and responses

Understanding how to inspect and modify incoming requests and outgoing responses is key for implementing custom security logic, such as API authentication, geofencing, and TOR relay blocking.

API Authentication

sub vcl_recv {
    if (req.url ~ "^/api" && req.http.Api-Key != "expected_key") {
        error 401 "Unauthorized";
    }
}

This VCL code snippet checks if incoming requests are targeting an API endpoint (indicated by the URL path starting with "/api") and verifies if the correct API key is provided in the request's headers. If the API key does not match the expected value, the request is denied with a 401 "Unauthorized" error response. This mechanism enhances security by ensuring that only requests with valid authentication can access API endpoints, protecting sensitive data and operations from unauthorized access.

Geofencing

This VCL code snippet restricts access to content based on the client’s geographical location. It checks if the client's country code matches the United States or its territories (Puerto Rico, American Samoa, Guam, Virgin Islands) and, if so, assigns the matching country code to a custom HTTP header (X-Country-Code), and then denies access by returning a 403 "Restricted Content" error. This mechanism is useful for enforcing geo-based access controls, ensuring that content is only available to users in specific locations while blocking access from others.

sub vcl_recv {
  if (client.geo.country_code ~ "(US|PR|AS|GU|VI)") {
    set req.http.X-Country-Code = client.geo.country_code;
    error 403 "Restricted Content";
  }
}

Leverage Edge Dictionaries

Edge Dictionaries are small, durable, globally consistent key-value stores for string keys and values, which offer extremely fast read performance (microseconds) at the edge and a separate HTTP API for writes. Dictionaries are ideal for storing configurations such as flags, A/B testing settings, path routing rules, and more. Updates to dictionaries made via the Fastly API are available at the edge within ~30 seconds.

Dictionaries have two primary parts: the dictionary container and the items within it. Once you attach a dictionary container to a version of your service and that service is activated, the data in the container (the dictionary items) become "versionless." This means that any updates to the items will take effect immediately, without requiring a new version of the service. We also expose a separate dictionary info resource to report up-to-date metadata about your dictionary.

Create a Dictionary

$ curl -i -X POST "https://api.fastly.com/service/${SID}/version/${VER}/dictionary" \

-H "Fastly-Key: ${YOUR_FASTLY_TOKEN}" \

-H "Content-Type: application/x-www-form-urlencoded" \

-H "Accept: application/json" \

-d "name=test-dictionary"

Add items to the Dictionary

$ curl -X POST "https://api.fastly.com/service/${SID}/version/${VER}/dictionary/test-dictionary/item" \

-H "Fastly-Key: YOUR_FASTLY_TOKEN" \

-H "Content-Type: application/x-www-form-urlencoded" \

-d "item_key=exampleKey&item_value=exampleValue"

Dictionaries serve as repositories for data that the NGWAF can utilize to make decisions regarding blocking. They function as containers that hold values used as conditionals in your VCL code, thus impacting how the WAF handles the request.

Referrer Blocklist

This uses custom VCL but is rewritten as if they used Edge Dictionaries. Dictionary items can be added, updated, or removed via the UI/API, it does not require cloning and activating versions. The table is created using API, and the logic in vcl_recv and vcl_error is custom VCL.

table bad_guys {
  "example.com" : "nope",
  "example2.com" : "nope",
  "example3.com" : "nope"
}
sub vcl_recv {
  set req.http.Referer-Host = regsub(req.http.Referer, "https?://([^/]+)/.*", "\1");
  set req.http.Referer-Check = table.lookup(bad_guys, req.http.Referer-Host, "yep");
  if (req.http.Referer-Check == "nope") {
    error 403;
  }
}

sub vcl_error {
   if (obj.status == 900 ) {
      set obj.http.Content-Type = "";
      synthetic {""};
      return(deliver);
   }
}

Doing more with the Next-Gen WAF

We hope that you found these tips and use cases helpful when coding VCL. Fastly VCL has the advantage of being easy to learn, and extremely fast and safe to execute at the edge. You can create custom builds, and functionality with VCL expands that – build something great with us! And if you’re not a customer yet, let’s chat about how it can help you build the best of the internet.