“DNS” URL redirect records considered harmful
Tags: https, redirect, dns, namecheap
Published: 2020-05-16 12:06:19

_Yes, I used "considered harmful" in the title. Can I be a thought-leader now?_

When you own a domain it is often desirable to use a subdomain to point to somewhere else. For example, you might want to use the cooler-looking `blog.mcornella.com` domain to point to your [dev.to](https://dev.to/mcornella) profile.

This can be done easily with a URL redirect record, where you specify the subdomain (`blog`) and the URL it should be redirected to (`https://dev.to/mcornella`). Fortunately, most major domain name registrars offer this option on their DNS settings dashboard. For example, this is how it looks in the current Namecheap DNS dashboard:

![Namecheap's add URL redirect record form](https://dev-to-uploads.s3.amazonaws.com/i/3qm3r54xxqgjxor7g1t1.png)
<figcaption>Namecheap's add URL redirect record form</figcaption>

![URL redirect record for blog.mcornella.com](https://dev-to-uploads.s3.amazonaws.com/i/vhbr5xj0f27cs3ratzmp.png)
<figcaption>URL redirect record for `blog.mcornella.com`</figcaption>

## How does this work?

Let's use `curl` to see what happens under the hood:

```console
$ curl -v blog.mcornella.com
*   Trying 162.255.119.141:80...
* TCP_NODELAY set
* Connected to blog.mcornella.com (162.255.119.141) port 80 (#0)
> GET / HTTP/1.1
> Host: blog.mcornella.com
> User-Agent: curl/7.65.3
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Server: nginx
< Date: Fri, 15 May 2020 14:49:06 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 47
< Connection: keep-alive
< Location: https://dev.to/mcornella
< X-Served-By: Namecheap URL Forward
<
<a href='https://dev.to/mcornella'>Found</a>.

* Connection #0 to host blog.mcornella.com left intact
```

We can see that the cURL request hits a Namecheap server (that uses Nginx, but that's not important here). This server then serves the redirect to the URL we set up, using a `Location:` header and an HTTP 302 status code.

What's more interesting is what we don't see. There are no TLS negotiation steps, and it's using port 80: **this request is not using HTTPS**.

## Security

Let's say we want to point somewhere else where security is crucial. In my case, I use `suport.mcornella.com` as a shortcut to the TeamViewer QuickSupport executable, so that my clients have it easier to download.

It's important that this is served using HTTPS all the way through, since it's something that users will end up running. Otherwise, an attacker could put themselves between the user and the Namecheap server, and modify the `Location` header with another URL pointing to a malicious payload masquerading as the TeamViewer QuickSupport executable.

Can we still use the previous method to do the redirect using HTTPS? This is what cURL says:

```console
$ curl -v https://blog.mcornella.com
*   Trying 162.255.119.141:443...
* TCP_NODELAY set
* connect to 162.255.119.141 port 443 failed: Connection timed out
* Failed to connect to blog.mcornella.com port 443: Connection timed out
* Closing connection 0
curl: (7) Failed to connect to blog.mcornella.com port 443: Connection timed out
```

As we can see, the Namecheap servers don't support HTTPS to make the redirect. *And why is that, you might ask.* Well, to do that, their servers don't just serve requests for our domain, they serve many other domains. **They'd have to respond to each subdomain request with a custom certificate**, which is significantly harder to do at the scale Namecheap operates in. It isn't impossible though, especially with [Let's Encrypt](https://letsencrypt.org/). Regardless, Namecheap doesn't support this at the moment, so let's see what alternatives we have.

## Securing the redirect

What do we need then? We need a hosting solution with a way to redirect to another endpoint with an automatically-generated certificate. I'll cover 2 alternatives: [Vercel](https://vercel.com/) (previously [Zeit Now](https://vercel.com/blog/zeit-is-now-vercel)), and [Netlify](https://www.netlify.com/).

### Vercel

For Vercel, you first need to have an account in [vercel.com](https://vercel.com). You can sign up with your GitHub account, as well as using other methods.

Next, [install the Vercel CLI](https://vercel.com/download) with `npm i -g vercel`. Then, login to Vercel from the CLI with `vercel login` and follow the instructions.

Next, we need to create a folder in which we'll add a `vercel.json` file, with the following content:

```json
{
  "redirects": [
    {
      "source": "/(.*)",
      "destination": "https://download.teamviewer.com/download/TeamViewerQS.exe",
      "permanent": true
    }
  ]
}
```

Two things to note here:
1. The `source` value (`/(.*)`) will match any path of the subdomain, so hitting `/`, `/abc`, or `/an/even/longer/path` will all redirect to the destination URL.
2. You should replace the value of `destination` with the URL you want to redirect to.

Once you have that, deploy the folder by running `vercel --prod` inside the folder we just created. This will by default get you a server running on `<site-name-with-dashes>.now.sh`, which is already ready to serve the redirects. How cool is that?

Finally, [set up the custom domain in Vercel](https://vercel.com/docs/v2/custom-domains), and replace the `URL redirect record` in Namecheap with a `CNAME` record pointing to `alias.zeit.co` (this is how it works up until now, follow the instructions in the linked Vercel docs if this doesn't work).

I've found that after doing the last step, this works pretty much right after the Vercel endpoint detects the custom domain change. Also, Vercel redirects HTTP requests to the appropriate HTTPS URL out of the box:

```console
$ curl -v suport.mcornella.com
*   Trying 35.180.16.12:80...
* TCP_NODELAY set
* Connected to suport.mcornella.com (35.180.16.12) port 80 (#0)
> GET / HTTP/1.1
> Host: suport.mcornella.com
> User-Agent: curl/7.65.3
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 308 Permanent Redirect
< Date: Fri, 15 May 2020 17:15:54 GMT
< Content-Type: text/plain
< Transfer-Encoding: chunked
< Connection: keep-alive
< Location: https://suport.mcornella.com/
< Refresh: 0;url=https://suport.mcornella.com/
< x-now-trace: cdg1
< server: now
< x-vercel-id: cdg1::rdj82-1589562954711-4fc270f67df9
< x-now-id: cdg1::rdj82-1589562954711-4fc270f67df9
<
Redirecting to https://suport.mcornella.com/ (308)
* Connection #0 to host suport.mcornella.com left intact
```

### Netlify

The setup with [Netlify](https://www.netlify.com/) is pretty much the same. You can also [sign up](https://app.netlify.com/signup) with GitHub and using other methods.

To [install the CLI](https://docs.netlify.com/cli/get-started/#installation), run `npm i -g netlify-cli`. Then, [login with `netlify login`](https://docs.netlify.com/cli/get-started/#authentication).

The redirect API of Netlify is also very similar. [There are two options here to specify a redirect](https://docs.netlify.com/routing/redirects/); I'll explain using a `_redirects` file. [Using the `netlify.toml` file allows extra options](https://docs.netlify.com/routing/redirects/#syntax-for-the-netlify-configuration-file), but we don't really need them here.

As before, create a folder where we'll put a file named `_redirects`, with the following content:

```
/*      https://download.teamviewer.com/download/TeamViewerQS.exe
```

The first part of the line is the original path to be matched (use `/*` to match all requests), and the last part is the destination path or URL.

Then, deploy the site by running `netlify deploy --prod` inside the folder we just created, making sure to specify `.` as the publish directory (default value).

When the site has been created, [add your custom domain](https://docs.netlify.com/domains-https/custom-domains) by following the instructions in the site dashboard. It'll ask you to add a CNAME pointing to the site URL created (`<site-name-with-dashes>.netlify.app`).

Finally, verify that both the HTTP and HTTPS requests work. In the case of Netlify, the HTTP requests aren't upgrading to HTTPS automatically, but the important thing is that HTTPS requests work just the same.

## Conclusion

Creating a URL redirect served via HTTPS is very easy and it costs nothing, and while some domain name registrars haven't caught up yet with the times, using Vercel and Netlify are two very good options which I'm sure you'll enjoy.