When we think about user experience, it’s usually things like “putting the user first”, “creating personas”, or “building an intuitive information architecture” that come to mind. We don’t often consider the emotions users might feel if they were hacked, as a result of using our applications.
Some common forms of security vulnerabilities can be protected against, by adding a few lines server configuration, to set additional HTTP response headers. These "security headers" can help protect users from Cross-site scripting (XSS)(external link), Clickjacking(external link), and Man-in-the-middle attacks.
Before going into detail about what headers we can set, it’s important to understand what an HTTP response header is, and how it fits into the bigger picture.
HTTP is the protocol which underpins the web. Based on the Client-Server architecture model, where a client (the user’s web browser) exchanges messages with a server (your website), HTTP is the messaging protocol clients and servers use to communicate.
When a user sends a message called a request, the request is processed by the website, which sends back a message called a response. Requests and Responses are sent back and forth as users navigate and interact with content on your site.
Let's take a look at the structure of HTTP messages in a bit more detail.
Request-Line / Status-Line
For requests, the Request-Line is the first part of the message. It specifies:
|HTTP method||Whether the client wants to receive or send data i.e. download an image or submit a form.|
|URI||The address the request should be sent to|
|HTTP protocol version||The version of HTTP being using by the client|
For responses, a Status-Line is the first part of the message and specifies:
|HTTP protocol version||The version of HTTP being using by the server|
|Status code||A numeric code indicating the type of response e.g. success is 200, resource not found is 404.|
|Response phrase||The reason for sending the status code|
The General-Header provides information about the message itself, as opposed to the content of the message. This can be information about the connection, the time and date the message was sent, or details around caching policies. Some common fields are:
|Date||The date and time the message was created|
|Cache-Control||Which caching mechanism the client or server should use|
|Connection||Whether or not the connection should remain open after the transaction completes|
Request-Header / Response-Header
For requests - a Request-Header is sent which provides further information about the request and about the client sending the request. It specifies:
|Accept-Encoding||Encodings that the client will accept|
|Accept-Language||The browser’s natural language settings|
|User-Agent||Browser and operating system details|
For responses - a Response-Header is sent and specifies similar information about the server:
|Age||The approximate amount of time since the response was generated|
|Location||If the requested resource have moved to a new location|
|Server||The software used by the server to handle the request|
The Response-Header is where security headers come into play, which we'll get to shortly.
Entity-Headers are most often used in responses but can also used in requests. when the client is sending content to the server, for example file uploads. The Entity-Header describes the data contained the Message-Body.
|Content-Encoding||Encodings that have been applied to the Message-Body|
|Content-Language||The natural language of the intended audience|
|Content-Length||The size of the Message-Body|
Requests often don’t have a Message-Body, for example when you request a web page, you’re not submitting information. A Message-Body is only used in a request when data is being sent to the server, for example a contact form submission or a file upload.
Enter Security Headers…
The default HTTP message headers do a good job of passing data back and forth, between users and your site, while maintaining a degree of integrity. For example the size of the Message-Body must match the Content-Length set in the Entity-Header.
However - there are ways to send additional malicious content in HTTP messages, and creative ways to use legitimate coding techniques, which result in bad user experiences.
Cross-site scripting (XSS)
This is one of the most common vulnerabilities found on the web. XSS occurs when an attacker injects a malicious script into a user’s request, the script is returned as part of the server response, and is executed by the user’s browser.
This is dangerous because injected script is executed in the same security context as legitimate scripts on your site. For example if the user is logged into your website, the injected script could perform authenticated actions, on the user's behalf.
The most common way of injecting a script is via the URL parameter, which is often seen on search pages.
If the keyword is displayed on the search results page, for example “showing 10 results for keyword”, the injected script could be executed.
Developers should always follow best practice and always sanitise user input, however, setting an additional field in the Response-Header adds an extra layer of protection against these types of attacks.
In Apache this is done simply by adding a line to the httpd.conf configuration file.
|Header always set X-Xss-Protection "1; mode=block"|
When browsers receive this header, some extra precautions are taken when executing scripts. If a script’s source is found in the request, the browser will throw an error, and the script won’t run.
Your best bet is to always sanitise input on the server, the X-Xss-Protection header is an extra safety net, just in case.
Congratulations! You won an iPad - click here to claim your prize…
Clickjacking is an attack where a malicious website tricks users into clicking something different to what they’re expecting to click. This is done by layering a malicious website over top of a legitimate website. When the unsuspecting user clicks “claim your prize” their click is passed through to a link or button on underlying legitimate website, which performs some action.
This might not seem like a big deal at first, but imagine the user is logged to the legitimate website on another tab, and gets tricked by the malicious site into clicking the “delete my account” button.
To protect users from Clickjacking attacks, which target your site, you can set the X-Frame-Options Response-Header.
|Header always set X-Frame-Options "SAMEORIGIN"|
Now malicious websites will not be able to pull through your website and overlay clickjacking content.
These attacks happen when a third party intercepts messages being sent between users and your website. Imagine a user submits their username and password, and a man-in-the-middle can read the content of that message, before it reaches the server.
This is commonly mitigated by using TSL (transport layer security) to encrypt user’s requests before they’re sent to the server. Anyone intercepting these messages gets an unreadable encrypted version. TSL (also referred to as SSL) connections are represented in browsers with a green padlock and URLs begin with “https”.
Sites using TSL will often support insecure connections as well, this provide backwards compatibility with older browsers, but means a user’s initial request may not be secure. For example, on a secure site, requests to http://example.com will be redirected to the secure https://example.com URL by the server.
Because the redirect to https happen on the server-side, any information transmitted by the user in the initial request, is vulnerable to man-in-the-middle attacks.
Adding a the Strict-Transport-Security Response-Header protects your users from this. It works by telling the user’s browser to always use https when communicating with your site. In the future, if a user enters an insecure “http” URL, the browser will redirect the request to https on the client-side, before the request is sent.
In Apache you can set this header like so:
|Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"|
At Somar, we challenge ourself to think about usability throughout the whole technology stack, not just at the surface level. A well configured server can impact user experience just as much as a well designed menu.
Like good design, good usability often goes unnoticed, while bad user experience really stands out. Setting security headers and following secure coding practices are good example of this. When it's there, it's transparent, and nobody notices. When it's missing - people notice for all the wrong reasons.
Security headers can be implemented easily, have great benefits for users, and are something we use in all of our projects.