HTTP headers are a crucial part of web app network communication. These headers are fields within HTTP responses and requests that provide specifications for activities like data handling and session verification, helping clients and servers effectively relay messages to each other. They often contain a wealth of valuable information, including client IP addresses, authorization credentials, and device model details.
Because of the importance of HTTP headers and the variety of data that they contain, they’re often a key target for attackers, who may attempt to access these headers to learn more about their targets, steal sensitive data, or manipulate user sessions. To combat this, you can configure security-focused HTTP header fields that help define how your app transmits data, loads resources, and executes scripts, making it harder for attackers to compromise your system.
Knowing which headers need to be configured for your app and making sure that they’re implemented correctly can be difficult. Synthetic testing helps you address these challenges by enabling you to check your security header configuration and see how it handles a wide variety of use cases. As a result, you can spot potential weak points in your app, better secure your existing headers, and configure new ones as necessary.
In this post, we’ll explore:
- How security headers work and how to configure them
- How to optimize your security headers with synthetic testing
How security headers work
Attackers can take advantage of insecure HTTP headers to breach apps in many different ways. For example, if a header doesn’t validate input properly, attackers can inject it with content such as malicious code. Alternatively, if an HTTP header doesn’t encrypt its response or request data, attackers may be able to simply eavesdrop on network communications. A few of the attacks that often take advantage of insecure headers are listed below:
Type of attack | Method of attack | Potential consequences |
---|---|---|
Cross-site scripting (XSS) | Injecting app components with code that penetrates the victim’s browser | The attacker is able to access information about user sessions, including cookies and authentication tokens, and pose as their victims to bypass authentication measures. They can also redirect from or manipulate app content. |
Web-cache poisoning | Injecting malicious data into the web cache system on a server | The attacker can make it appear that an app is down, redirect users to websites designed to steal their information, or download malware onto their devices. |
Clickjacking | Rendering content within a compromised frame contains hidden links or buttons | The attacker can make it appear that an app is down, redirect users to websites designed to steal their information, or download malware onto their devices. |
Man-in-the-middle (MITM) | Eavesdropping on unencrypted client-server communications through methods such as sniffing | The attacker is able to steal sensitive user data, often security credentials, payment details, or personally identifiable information (PII). |
To prevent attacks such as these, you can configure specific headers to secure different aspects of your app. The security headers that are the most relevant for your use cases may differ based on the types of content and resources you handle. For instance, there are certain headers that every app should use to protect against the most common attacks. These include X-Content-Type-Options
to prevent your app from executing certain scripts and carrying out XSS attacks, HTTP Strict Transport Security (HSTS)
to encrypt your data, and X-Frame-Options
to prevent your content from being embedded into compromised frames. However, apps that handle sensitive data, such as PII, may want to also implement more advanced headers. These can include Content-Security-Policy
and Trusted Types
, which provide extra protection against XSS attacks.
Configuring security headers
In most cases, you can configure security headers by adding them to a web server configuration file. If you don’t have access to these files—which is common when using a shared hosting service—you may be able to use an alternative, like an .htaccess
file, instead.
You’ll want to customize your header setup to maintain a good balance between securing your app without severely impacting app functionality or performance. For example, configuring the X-Frame-Options
header enables you to prevent clickjacking attacks by limiting the ability of your app to render content within frames. If your app doesn’t use any frames, you’ll likely want to use the strictest option and prevent any content framing:
NGINX | Apache |
---|---|
add_header X-Frame-Options “DENY” always; | Header always set X-Frame-Options “DENY” |
However, if your app does incorporate frames, you may instead want to restrict frame use according to a same-origin policy:
NGINX | Apache |
---|---|
add_header X-Frame-Options “SAMEORIGIN” always; | Header always set X-Frame-Options “SAMEORIGIN” |
Additionally, for more granular customization options, you may want to use a more modern alternative to X-Frame-Options
—the Content Security Policy
frame-ancestors
directive—instead. frame-ancestors
enables you to define specific trusted sources to allow frame embedding from:
NGINX | Apache |
---|---|
add_header Content-Security-Policy “frame-ancestors ‘self’ https://example.com;”; | Header always set Content-Security-Policy “frame-ancestors ‘self’ https://example.com;” |
You may want to use both X-Frame-Options
and frame-ancestors
together, as the former is more likely to be supported by older browsers, while the latter offers a better experience for modern browsers. Note that when implemented together (and both are supported), browsers will ignore X-Frame-Options
in favor of frame-ancestors
.
Optimize your security headers with synthetic testing
Given the long list of configuration best practices recommended for security headers, making sure that the most relevant headers for your app have been added and implemented correctly can be challenging. By enabling you to test how your app transmits header data and handles user security, synthetic testing can help you detect potential gaps in your security header strategy.
Datadog Synthetic Monitoring provides out-of-the-box templates that enable you to quickly check security header configuration for your app. You can use the Security Headers
template to quickly determine whether your application has a few key headers properly implemented, including X-Content-Type-Options
, X-Frame-Options
, Content-Security-Policy
, and HSTS
.
You can also easily customize the default security header code when creating your test to add or remove specific headers. For example, many browsers automatically restrict cross-origin resource sharing (CORS) to prevent cross-site request forgery (CSRF) attacks, where a bad actor uses session information to pose as a victim and execute certain actions. Let’s say your app does need to access cross-origin resources—to load TrueType fonts or WebGL textures, for instance. In this case, you’ll want to enable CORS headers to safely load resources from certain websites. To add a check for the recommended CORS configuration in the Security Headers
template for these headers, you can add the following code:
dd.expect(dd.response.headers).to.have.property(‘access-control-allow-origin’);
const hAcao = dd.response.headers[“access-control-allow-origin”];
dd.expect(hAcao).to.equal("https://example.com");
dd.expect(dd.response.headers).to.have.property(‘access-control-allow-credentials’);
const hAcac = dd.response.headers[“access-control-allow-credentials”];
dd.expect(hAcac).to.equal("true");
Alternatively, using the Information Disclosure
template, you can easily detect misconfigurations that could leave your app vulnerable to security disclosure attacks. Tests created with this template will provide you with recommendations for protecting your app data, such as removing the X-Powered-By
and Server
headers to hide key server information.
Use Datadog Synthetic Monitoring to secure your headers
Customizing security headers can help protect your app against a number of attacks. However, actually knowing which ones to configure and how can be a challenge. Synthetic testing helps you ensure that these headers are implemented correctly and aren’t exposing key information or entry points for attackers. This is a particularly critical step for organizations that handle sensitive data or have to otherwise meet strict compliance requirements.
You can get started with Datadog Synthetic Monitoring using our documentation. Or, if you’re not yet a Datadog user, you can sign up for a 14-day free trial.