Securing Web-Based Applications/Platforms with Proper Response Headers
Discover HTTP security headers, Permissions Policy, and Content Security Policy as discussed by Kuldeep Pisda.
This article breaks down the talk by Kuldeep Pisda, Lead Software Engineer at STGI, during the recent DevOps meet-up at GeekyAnts.
How can one secure the front-end of an application? When it comes to security, people usually talk about setting up firewalls and other network security measures.
However, one basic thing we can do to make the front-end more secure is to avoid touching anything that comes from it, as backend developers know all too well. The front-end is often vulnerable to manipulation, and we want to prevent that.
Rather than discussing why the front-end is not secure, this article focuses on what we can do to improve its security. We will discuss how to accomplish this without directly modifying the front-end code.
How to Increase Trustworthiness in Front-end Development?
As a back-end developer, it can be difficult to trust the front-end. How can we increase its trustworthiness? When securing the entire infrastructure, many parameters need to be considered, such as configuring the routing table, opening and closing ports, and ensuring the front-end application we build does not compromise our backend or cloud infrastructure.
When coding from the back-end perspective, we often use strict validations to ensure the security of our application. It is important to keep these validations, as they are essential for auditing and other security measures. To improve the trustworthiness of the front-end, we should implement these strict validations and security measures to ensure the integrity of our entire infrastructure.
How to Secure the Front-end?
Let us look at a list of some basic and common things that we can think of when we are talking about making the front-end secure in general:
HTTP Security Headers
Content Security Policy (CSP)
This article will focus mostly on three things from this list:
How can we use an HTTP security address?
How can we define Permissions Policy?
How to define CSP address?
These three things ensure that at least whatever code is getting executed in the browser is a bit more trustworthy.
HTTP Security Headers
We develop applications, but we must also be aware of phishing. Phishing is when hackers create pages that look similar to legitimate ones. You may have received messages on WhatsApp claiming that clicking a link will get you a free recharge, but it's a phishing scam. And this is not the only way phishing occurs.
Sometimes, hackers will iframe your website. As developers, we know that iframe content can be controlled. Hackers can iframe your entire website and circulate it globally, exposing users' data to them.
So how can we prevent this? The solutions to this problem are simple, but we may not be aware of them or might not take action due to various reasons.Using proper HTTP security headers, we can prevent these basic attacks. For example, can we prevent iframing? It is within our control, and that's what these headers are for.
Strict-Transport-Security ensures that communication is done only through HTTPS.
Tracking systems and analytics use an API call that looks like an image load to avoid ad blockers. We can define who can iframe us with the X-Frame-Options header to prevent this from happening on our application engine. We can allow websites of the exact origin to iframe us or prevent anyone from doing it.
X-XSS-Protection helps prevent cross-site scripting in the front-end by escaping the output.
Access-Control-Allow-Origin is a basic header that can enhance the security of a front-end application if added to the application.
We integrate third-party systems into our applications using widgets, libraries, and frameworks. We can prevent issues by using the permissions policy item. Though it is time-consuming to set up at first, it helps define permissions at a very minute level. For example, we can specify that only a particular plugin can use the camera. We can also discard any source that originates from a domain other than our own.
We define permission policy response headers in the HTTP response. Browsers are expected to strictly enforce these headers. Good browsers like Mozilla, Firefox, and Beat Pro respect these headers. If permission is not allowed, these browsers will ensure that the source is not allowed, even if the code is run from the console. This gives us hope that our front-end application is more secure.
The Content-Security-Policy header is like a dictionary of what is allowed on the front-end side. In this header, we define very specific rules.
The browser respects the response that we put in the header and ensures that anything loaded follows the rules mentioned. We can even specify which API endpoints we can access and what kind of API calls we can make to certain endpoints, ensuring that our front-end only makes API calls to the intended sources.
By using the Content-Security-Policy header, we can create a secure environment for our front-end and prevent unauthorized access and malicious activities.
How to Find Which Values to Put in the Headers?
The bigger question is how to make the headers. How can we determine which values to put in each header? It's not rocket science, just laborious work.
Some business clients had hired a security consulting company and requested that we block patch calls to a simple static application. They insisted that we block PUT, PATCH, DELETE calls, and other such actions. We went to an ethical hacking company and asked them what to do. Let us look at the approach we took to ensure that our company's web application is A+ secure.
Headers have specific use cases. If we take the X-Frame-Options header, it is used to specify which sources can iframe your website. It is important to separate the cloud team and create a list of sources. Once it is done, you will only have to revisit it if you are making significant changes to your application.
For instance, the Permissions-Policy header defines the type of permission the application will be using. If you are using the user's location, you will use the location data from the browser's API call. Third-party libraries like video libraries such as Agora usually have documentation of how you can update your permissions policy.
In our case, the front-end team was not very cooperative, so we started with a hard approach by disallowing everything in the cloud-front distribution. We analyzed the console logs to see which sources were not listed. Then, we copied and updated it in the header. This may be a laborious task initially, but once completed, it will be worth it.
The Content-Security-Policy header is even more laborious. If you are working with many third-party systems, you do not know what API calls they're making or where they are loading the images from. You can either take the hard way or sit with the front-end team and document everything.
How Do We Set These Response Headers?
This mostly relies on two things. First, it is essential to understand how it is deployed in general. The reason is that it is not a back-end server. In a backend server, we have control of the response headers in the API call itself. In contrast, it is the front-end and static. It does not compute on the go. Therefore, headers such as the content security policy tag can be added to the HTML tag itself. These headers can be defined as meta tags in the HTML code itself, allowing us to have a source of truth.
If you are going with a cloud provider, they usually give the option to configure response headers. For example, CloudFront has a policy where we can define a set of response errors that we can attach to our CloudFront distribution.
If you are not using any cloud providers, we can take a simpler approach and use an EC2 machine and build it behind an Nginx. In that configuration, we have to add those configurations in the Nginx config file. The job of returning the response will be of the Nginx server, not of the static build. We can define a set of addresses we want to return for a specific location.
Likewise, if you are going with Kubernetes, it can already configure those things in the YAML file we define.
We can define the requirements for a secure front-end without necessarily testing it. Here are some ways to enhance front-end security:
Implement secure coding practices
Use HTTPS protocol to encrypt data in transit
Validate input to prevent injection attacks
Use authentication and authorization mechanisms
By implementing HTTP security headers, permissions policy, and content security policy, we can significantly enhance the security of our web-based applications and platforms.
Check out the full DevOps Meetup discussion here.
This article was written by Ahona Das, Technical Content Writer, for the GeekyAnts blog.