Preventing web browsers from doing what attackers tell them to

Security Headers

Article from Issue 157/2013
Author(s):

Kurt explains how using security headers can provide extra protection from malicious content and web attacks.

If you remember when web apps were simple and hosted on a single site, you are by definition old; however, you probably also know that when apps are networked, the whole is greater than the sum of its parts.

For example, suppose you have two separate web apps, such as your retirement fund web site and a mortgage calculation web site, that are useful apps on their own. However, if you link these apps together, allowing users to specify their income and how much they currently pay for rent/mortgage and then calculate what kind of mortgage they can afford, then the whole thing is much more useful because they can figure out whether it's better to put money into their retirement fund or their mortgage payments and test various financial scenarios. You could also tie these into additional applications and sites, like your mutual funds, your tax calculations, and so on for even more functionality.

Of course, all this functionality comes at a cost: complexity. And, this added complexity gives attackers more avenues of approach. For example, an attacker could embed a copy of your bank's website using an iframe within a hostile site that they control. This hostile site could have JavaScript that records all your key presses, so when you log in to your bank site, the password is sent to the attacker. Within an application, an attacker also can exploit cross-site scripting (XSS) to embed malicious JavaScript or content into a page to redirect the form data when you hit Submit. So, what's the solution? Layering more security (and complexity) onto the whole mess, of course!

Strict-Transport-Security

Strict-Transport-Security is one of the simplest and most effective of the new security headers. HTTP Strict Transport Security (HSTS) allows you to specify that a domain (and optional subdomains) should only be served over HTTPS instead of HTTP. The idea is that when a user accesses your website from a safe location the first time (e.g., they register from home), you send them an HSTS header saying "user HTTPS for at least the next year." Then, when the user accesses your site from a coffee shop, for example, their browser only allows access to it via HTTPS, preventing man-in-the-middle attacks. In Apache, you can add the following header to serve HSTS headers for this site and all subdomains that are valid for 180 days:

Header set Strict-Transport-Security "max-age=15552000; includeSubDomains"

HSTS headers should only be served over HTTPS; so, to get people from your HTTP site to your HTTPS site, I recommend using a redirect. Alternatively, you can get whitelisted in some browsers (well, in Google Chrome [1]), which is ideal because then clients will always be protected.

X-Frame-Options

To prevent framing by hostile sites, you can specify which sites are allowed to put your content within an iframe. The problem is that this action is handled on the client side, and not all browsers support X-Frame-Options or all the capabilities they provide [2].

In that case, your best bet is either to set it and hope for the best or to do browser detection and use some JavaScript to see whether the window is "on top." Note, however, that you won't easily be able to allow it to be framed by specific sites and blocked by others (which is easy with X-Frame-Options).

X-Frame-Options has three settings: Deny, which means no framing is allowed at all; Allow-From, which lets you list specific sites and URLs that can embed the page in an iframe; and SAMEORIGIN, which allows anything from the same origin (basically the same domain) to embed it within an iframe.

SAMEORIGIN makes it easy to protect the content but still allow embedding by other pages on your site. This occurs at the risk that a page that doesn't need to embed the content has an XSS vulnerability that can be tricked into doing so. The XSS can then be used to inject JavaScript that copies the keystrokes, for example. If possible, you should use Deny for any content that should never be embedded and use Allow-From specifically to allow resources to be embedded as needed.

Access-Control-* Headers

With the modern tendency to combine web applications across multiple domains and organizations, you need to allow a web page on site A to trigger a request to site B (e.g., for an image or form). Traditionally, this behavior has led to a lot of security problems. For example, attackers can get users to visit a hostile site or load hostile content (e.g., by serving it over an ad network) and then trigger their web browser to load elements from another site, such as their bank, or their email service. Here, however, you run into a chicken-and-egg problem.

If you visit site A, and it tells you to load a resource from site B, how does your web browser know whether this action is allowed? Even if site B has a security policy with data served via HTTP headers that will let you know whether your browser is allowed to make the request, how do you know whether you are supposed to do so? The solution is that your web browser makes a "preflight" request, using the OPTIONS request method (as opposed to GET, POST, TRACE, and so on) for the resource, at which time site B's security policy is served via HTTP headers. Your web browser then processes these headers and decides whether or not it is allowed to make the request.

A large number of Access-Control-* headers [3] are available that you can send (Table 1). Basically, you can control which URLs are allowed to make requests, how the request can be made, whether the client can send credentials when making the request, which headers the client can use, and more.

Table 1

Various Access-Control-* Options

Access-Control-* Header

Function

Access-Control-Allow-Origin

URI that may access this resource (e.g., *, *.example.org)

Access-Control-Expose-Headers

Headers the browser is allowed to access

Access-Control-Max-Age

How long it can be cached by the browser

Access-Control-Allow-Credentials

Whether or not credentials can be used in the request

Access-Control-Allow-Methods

Methods allowed to be used by the browser (e.g., GET, POST, etc.)

Access-Control-Allow-Headers

Which headers can be used when making the request

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News