Defending Against Web Attacks: X-Frame Options 2023

In this article we will discuss about Defending Against Web Attacks.

Introduction[Defending Against Web Attacks]:

In this web world we have seen various common attacks like XSS, Clickjacking, Session Hijacking etc. Various HTTP headers are introduced to defend against these attacks in a simple and easy way. In this series of articles, we’ll see the various headers available to protect against common web attacks, and we’ll also see a practical approach to implementing them in a simple PHP-based application.

The goal of this series is to give developers a practical feel for how these common attacks can be prevented by simply using some HTTP headers. We will setup a vulnerable application to understand these headers in detail.

Lab setup:

You can download the code snippets and database file used in this application here:

[download]Click here to download[/download]

You can setup this PHP-MYSQL application in XAMPP or WAMP or LAMP or MAMP, depending on your computer.

In my case, I’m using a Mac, so I’m using MAMP, and I’ve saved all the files in a folder called “sample” in my root directory.

Application functionality:

After setting up the sample application, launch the home page as shown below.

http://localhost/sample/index.php

As we can see in the image above, this application has a very simple login page where the user can enter their login details. It has basic server-side authentication as explained below.

User input fields cannot be empty. This is done using the PHP empty() function. So if the user doesn’t enter anything and clicks on login, the message will appear as below.

If the user enters wrong credentials, it throws a message as shown below. This is done after performing a check against user database.

If the user enters the correct username and password, the home page for the logged in user will be displayed.

This is done using the MySQLi prepared command as shown below.

[sql]
$stmt = $mysqli->prepare(“select * from admin where username=? and password=?”);

$stmt->bind_param(“ss”,$username,$password);

$stmt->execute();

username: admin
password: 1q2w3e4r5t
[/sql]

Note: Please note that the given password is stored as a SHA1 hash in this sample database. This is a common password and this SHA1 hash can be easily cracked using some online tools.

After logging in, a session is created for the user and there is a simple form that is vulnerable to XSS.

Now launch BurpSuite and note the default headers that are set when we log into this application. It looks like below.

[simple]
HTTP/1.1 200 OK

Date: Sun, 12 Apr 2015 13:59:23 GMT

Server: Apache/2.2.29 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.8 PHP/5.6.2 mod_ssl/2.2.29 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5. 20.0

X-Powered-By: PHP/5.6.2

Expires: Thu, 19 Nov 1981 08:52:00 GMT

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Pragma: no-cache

Set-Cookie: PHPSESSID=17807aed72952730fd48c35ac8e58f9c; path=/

Content-length: 820

Keep-Alive: time limit=5, max=100

Connection: Keep-Alive

Content-Type: text/html; character set=UTF-8
[/simple]

As long as you clearly follow the above headers, no headers are added to provide additional security to this application.

After logging in we can also see a search box that accepts input from the user and returns back to the user.

:</text><?php echo $text; ?></div>

</div>

</form>

</center>
</div>

</body>
</html>
[/php]

Clickjacking prevention using X-Frame-Options header:

The first concept that we will discuss is Clickjacking mitigation using X-Frame-Options.

How does it work?

Usually, an attacker loads a vulnerable page into an iframe to perform clickjacking attacks.

In our case, we are going to load the user dashboard page into an iframe as shown below. This page appears after successful login.

http://localhost/sample/home.php

[html]
<!DOCTYPE html>
<html>
<head>
<title>iframe</title>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
</head>
<body>
<iframe src=”http://localhost/sample/home.php”></iframe>
</body>
</html>
[/html]

Related article:CashApp Carding updated ultimate method and bins 2023

I saved this page as iframe.html on the same server. When we load this in a browser, the above URL will be loaded in an iframe as shown below.

While there are several ways to avoid this, we will discuss the X-Frame-Options header to keep the content of this article consistent with the title.

The X-Frame-Options header can be used with the following three values:

DENY: Denies any resource in the target’s framing.

SAMEORIGIN: Allows only resources that are part of the same-origin policy to frame the protected resource.

ALLOW-FROM: Allows a single serialized origin to frame a protected resource. This only works with Internet Explorer and Firefox.

We will discuss each of these options in detail.

X-Frame-Options: DENY

Let’s start with “X-Frame-Options: DENY”.

Open your home.php file and add the following line.

header(“X-Frame-Options: DENY”);

Now the modified code should look like below.

[php]


Admin Home Page

Welcome to the main panel…

You are logged in as: [logout]

[/php]

Log out of the application and log back in so that you can now monitor the HTTP headers.

Below are the HTTP headers from the server after adding the X-Frame-options header with the DENY value:

[simple]
HTTP/1.1 200 OK

Date: Sun, 12 Apr 2015 14:14:51 GMT

Server: Apache/2.2.29 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.8 PHP/5.6.2 mod_ssl/2.2.29 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5. 20.0

X-Powered-By: PHP/5.6.2

Expires: Thu, 19 Nov 1981 08:52:00 GMT

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Pragma: no-cache

Set-Cookie: PHPSESSID=9190740c224f78bb78998ff40e5247f3; path=/

X-Frame-Options: DENY

Content-length: 820

Keep-Alive: time limit=5, max=100

Connection: Keep-Alive

Content-Type: text/html; character set=UTF-8
[/simple]

If you notice, there is an extra header added in the response from the server.

Now if we reload the iframe, the URL will not load inside the iframe. It looks like below.

Let us see the reason behind this by navigating to Chrome’s developer tools using the following path.

Customize and Control Google Chrome -> More Tools -> Developer Tools

As we can see in the above figure, this is because of the header we set in the server response.

We can check the same in Firefox by using the Web Developer Extension as shown below.

If we load the iframe.html page in Firefox, below is the error being displayed in the console.

X-Frame-Options: SAMEORIGIN

There may be situations where framing of this URL is required for this application. In such cases, we can allow same-origin framing and prevent it from cross-origin requests by using the “SAMEORIGIN” value with the X-Frame-Options header.

Open your home.php file and add the following line.

header(“X-Frame-Options: sameorigin”);

Now the modified code should look like below.

[php]


Admin Home Page

Welcome to the main panel…

You are logged in as: [logout]

[/php]

Log out of the application and log back in so that you can now monitor the HTTP headers.

Below are the HTTP headers from the server after adding the X-Frame-options header with the sameorigin value:

[simple]
HTTP/1.1 200 OK

Date: Sun, 12 Apr 2015 14:34:52 GMT

Server: Apache/2.2.29 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.8 PHP/5.6.2 mod_ssl/2.2.29 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5. 20.0

X-Powered-By: PHP/5.6.2

Expires: Thu, 19 Nov 1981 08:52:00 GMT

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Pragma: no-cache

Set-Cookie: PHPSESSID=5f3d66b05f57d67c3c14158621dbba9e; path=/

X-Frame-Options: same origin

Content-length: 820

Keep-Alive: time limit=5, max=100

Connection: Keep-Alive

Content-Type: text/html; character set=UTF-8
[/simple]

Now let’s see how it works with different origins.

First, load the same iframe.html file that is hosted on the same server.

As we can see in the image below, we are able to load the page in an iframe without any problem.

Now, I launched Kali Linux using Virtual Box and loaded this URL(http://localhost/sample/home.php)and placed the file on the server, which is a different origin for our current application.

Below is the code snippet used on the Kali Linux machine to create iframe.html.

When we launch this iframe.html file, it will not load due to the cross origin restriction by the server.

We can see that in the error console of iceweasel browser in Kali Linux as shown below.

The error clearly shows that the server does not allow cross-origin framing.

X-Frame-Options: ALLOW-FROM http://www.site.com

X-Frame-Options: ALLOW_FROM option allows a single serialized-origin to frame the target resource. This works only with Internet Explorer and Firefox.

Let us see how this works.

First, open up your home.php file and add the following line.

header(“X-Frame-Options: ALLOW-FROM http://localhost”);

Now the modified code should look as shown below.

[php]
<?php session_start(); session_regenerate_id(); header(“X-Frame-Options: ALLOW-FROM http://localhost”); if(!isset($_SESSION[‘admin_loggedin’])) { header(‘Location: index.php’); } if(isset($_GET[‘search’])) { if(!empty($_GET[‘search’])) { $text = $_GET[‘search’]; } else { $text = “No text Entered”; } } ?>
<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>Admin Home</title>
<link rel=”stylesheet” href=”styles.css”>
</head>
<body>

<div id=”home”>
<center>
</br>
<legend><text id=text><text id=”text2″>Welcome to Dashboard…</text></br></br> You are logged in as: <?php echo $_SESSION[‘admin_loggedin’]; ?> <a href=”logout.php”>[logout]</a></text></legend>

</br>

<form action=”” method=”GET”>

<div id=”search”>
<text id=”text”>Search Values</text><input type=”text” name=”search” id=”textbox”></br></br>

<input type=”submit” value=”Search” name=”Search” id=”but”/>

<div id=”error”><text id=”text2″>You Entered:</text><?php echo $text; ?></div>

</div>

</form>

</center>
</div>

</body>
</html>
[/php]

Let us logout from the application and re-login to check if the header is added.

[plain]
HTTP/1.1 200 OK

Date: Mon, 13 Apr 2015 02:18:49 GMT

Server: Apache/2.2.29 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.8 PHP/5.6.2 mod_ssl/2.2.29 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5.20.0

X-Powered-By: PHP/5.6.2

Expires: Thu, 19 Nov 1981 08:52:00 GMT

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Pragma: no-cache

Set-Cookie: PHPSESSID=c8a5b9a76982ae38f0dde3f3bf3480f5; path=/

X-Frame-Options: ALLOW-FROM http://localhost

Content-Length: 820

Keep-Alive: timeout=5, max=100

Connection: Keep-Alive

Content-Type: text/html; charset=UTF-8
[/plain]

As we can see, the new header is added now. If we now try to load the iframe from the same server, it loads the page without any problem, as shown below.

This is because http://localhost is allowed to load this URL.

Now let’s try changing the header to something else and try loading it again.

Add the following line to home.php and observe the difference.

header(“X-Frame-Options: ALLOW-FROM http://www.androidpentesting.com”);

The modified code should look like this.

[php]


Admin Home Page

Welcome to the main panel…

You are logged in as: [logout]

[/php]

The following are headers captured from BurpSuite.

[simple]
HTTP/1.1 200 OK

Date: Mon, 13 Apr 2015 02:20:26 GMT

Server: Apache/2.2.29 (Unix) mod_fastcgi/2.4.6 mod_wsgi/3.4 Python/2.7.8 PHP/5.6.2 mod_ssl/2.2.29 OpenSSL/0.9.8y DAV/2 mod_perl/2.0.8 Perl/v5. 20.0

X-Powered-By: PHP/5.6.2

Expires: Thu, 19 Nov 1981 08:52:00 GMT

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Pragma: no-cache

Set-Cookie: PHPSESSID=6a8686e1ab466a6c528d8a49a281c74e; path=/

X-Frame-Options: ALLOW-FROM http://www.androidpentesting.com

Content-length: 820

Keep-Alive: time limit=5, max=100

Connection: Keep-Alive

Content-Type: text/html; character set=UTF-8
[/simple]

Now if we refresh our previous link it won’t load the page in the iframe.

If we observe the error console, it shows the following error.

It is obvious that framing by http://localhost is not permitted.

Conclusion

In this article, we have seen the functionality of our vulnerable application and fixed the clickjacking vulnerability using X-Frame-Options header. We have also seen various options available with this header and how they differ from each other. The next article gives coverage of other security headers available.

Leave a Reply

Your email address will not be published. Required fields are marked *