2022-07-18

1658116800
guides
 18 Jul 2022  guides

Restricting Netlify's Default Subdomain for Security and SEO

By default, there’s no way to remove the default subdomain that Netlify provides when creating a site. While it’s possible to rename it, the default subdomain cannot be removed as the namespace is used for unique deploy URLs and other use cases within Netlify that require a site-specific label.

This behavior can be a dynamic problem for some users. The primary domain that points to a site hosted on Netlify is often protected or optimized through DNS proxies such as Cloudflare. Being able to access the site via the default subdomain defeats much of the benefits of this proxying (especially for sites using Netlify’s free tier where bandwidth is limited).

Secondly, if the content on a site is required to be behind a zero-trust Secure Access Service Edge (SASE) perimeter such as Cloudflare Teams, then simply being able to bypass that domain-level protection poses a security risk.

In either case, it’s not ideal for anyone to be able to access the site’s content via its default subdomain. To workaround this problem, it’s possible to include a redirect that will reroute any traffic sent to the default subdomain to the primary domain instead.

Creating the Redirect Rule

Netlify offers a few ways to implement redirects. For simplicity though, deploying a _redirects file is the most straightforward approach. The syntax for redirecting the default subdomain to the primary domain is as follows:

https://paramdeo.netlify.app/* https://paramdeo.com/:splat 301!

The 301 HTTP status code is used to make search engines aware of the Permanent Redirect and deduplicate any content previously crawled on the default subdomain.

While not strictly necessary, the :splat directive will pattern-match and transfer any URL paths over to the primary domain. This is also good for SEO edge cases, and it doesn’t hurt to include it either way.

Tackling the Deploy URL Threat Model

Since unique deploy URLs are prefixed with the deploy ID, and there’s no wildcard pattern in the redirect syntax just yet, the redirect rule will not affect viewing of unique deploy URLs. For example, the following will still be accessible:

https://8a6a090b328a01b326c93d9d--paramdeo.netlify.app

This is usually an acceptable outcome: any guessing or navigating to the default subdomain will redirect to the primary domain, and deploy URLs can still be viewed as necessary since the chances of the deploy URL being known are minimal.

But what about sites that are required to only be accessed via authentication and authorization? This could include a private message board, an intranet site, or a personal knowledge base (second brain).

I came across a quirk in Netlify that effectively makes the deploy preview URLs unable to be viewed, without affecting the deploy process itself, or the primary domain.

There are a few things I noticed. First, a deploy ID is usually 24 characters in length, for example:

62d60df247c2c2252ac15247

Deploy IDs are always prefixed to the default subdomain with two dashes -- as a delimiter:

62d60df247c2c2252ac15247--paramdeo.netlify.app

Here’s where it gets interesting.

According to RFC 1035 there are restrictions on the length of subdomain labels. Below is a verbatim snippet from the RFC entry:

[...] labels must follow the rules for ARPANET host names.  They must start with a letter, end with a letter or digit, and have as interior characters only letters, digits, and hyphen.  There are also some
restrictions on the length.  Labels must be 63 characters or less.

Subdomains therefore have a limit of 63 characters in order to be RFC compliant. You can go ahead and try to add a 64 character subdomain into any DNS provider. In Cloudflare for example, you’d run into the following error:

DNS Validation Error (Code: 1004) DNS name is invalid.

Reduce the subdomain length to 63 characters and it will be instantly valid. While that error message is specific to Cloudflare, Netlify also uses similar validation for their default subdomains:

And here’s where the workaround comes into play.

The complete URL for a unique deploy will have the deploy ID prepended to the default subdomain — behavior that’s not completely unknown — thereby breaking the deploy URL’s RFC compliance. Navigating to such a URL will simply not resolve.

For the deploy URL be valid, the default subdomain needs to be at most 37 characters long, and the total deploy URL will be 63 characters in length; RFC compliant and therefore viewable:

# Doesn't resolve over HTTP

https://62d60df247c2c2252ac15247--86091c086f35c1dea6a43da526a1d09b36c7e2d147efe2b132acb022f7bfb06.netlify.app

# Resolves over HTTP

https://62d60df247c2c2252ac15247--86091c086f35c1dea6a43da226a1d09b36c7e.netlify.app

This can therefore be exploited in the following way:

  1. Ensure the _redirects syntax covers the default subdomain ⟶ primary domain redirect
  2. Change the default subdomain name to a string that’s 63 characters in length

Resulting deploy URLs will be inaccessible, and navigating to the default subdomain itself will result in a redirect to the primary domain.

It’s important to note that this is ONLY applicable to edge-cases where access via the primary domain requires authorization, and access to the default subdomain and deploy URLs is undesirable.

One last thing: this kind of workaround breaks the preview and collaboration aspects of Netlify, and so local previewing and building (with the Netlify CLI used for deploying the build directory) would be the assumed workflow — in such aforementioned cases as private message boards, intranet sites, personal knowledge bases, etc.

Webmentions & Comments

Copyright © Paramdeo Singh · Made with ☕️ in 🇬🇾 · All Rights Reserved

Last Site Build on 14 Aug 2022

1MB Club Badge

Paramdeo Singh Guyana

Riding the wave of consciousness in this treacherous mortal sea.

Technology Design Strategy Literature Personal Blogs