DEV Community

Marc Cornellà
Marc Cornellà

Posted on • Edited on

“DNS” URL redirect records considered harmful

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 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

Namecheap's add URL redirect record form

URL redirect record for blog.mcornella.com

URL redirect record for `blog.mcornella.com`

How does this work?

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

$ 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
Enter fullscreen mode Exit fullscreen mode

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:

$ 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
Enter fullscreen mode Exit fullscreen mode

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. 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 (previously Zeit Now), and Netlify.

Vercel

For Vercel, you first need to have an account in vercel.com. You can sign up with your GitHub account, as well as using other methods.

Next, install the Vercel CLI 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:

{
  "redirects": [
    {
      "source": "/(.*)",
      "destination": "https://download.teamviewer.com/download/TeamViewerQS.exe",
      "permanent": true
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

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, 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:

$ 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
Enter fullscreen mode Exit fullscreen mode

Netlify

The setup with Netlify is pretty much the same. You can also sign up with GitHub and using other methods.

To install the CLI, run npm i -g netlify-cli. Then, login with netlify login.

The redirect API of Netlify is also very similar. There are two options here to specify a redirect; I'll explain using a _redirects file. Using the netlify.toml file allows extra options, 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
Enter fullscreen mode Exit fullscreen mode

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 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.

Top comments (1)

Collapse
 
designerdoesdev profile image
Keith Radcliffe

Hey Marc, this was excellent it was almost the right fix for the issue I was seeing. I bought a .dev domain on NameCheap a couple of days ago and it kept timing out on the redirects. So I carried out what you have done here with Vercel and it was actually a little bit easier in that I created the project with the redirect (to my Dev.To currently empty blog :D) and then applied the TLD directly to the project, I didn't need a subdomain for my purposes.

This was excellent advice, bookmarked for future reference thanks so much for the help!