The State of XSS: Best practices for a secure web experience

Welcome as web continues to evolve, it's become increasingly challenging for developers to build secure web experiences that users can trust.

Cross-site scripting tacks on the rise.

So what can we do to help defend them?

This Presentation will review what cross-site scripting is all about, and the impact that continues to have on web applications today.

It looks the different types of attacks and review best practicesyou can adopt to help protect your users from being exploited.

Lastly, I've a mitigation checklist, which you can use to help assess how protected your users are against these of type of attacks.

Let's get started So cross-site scripting or XSS for short is a type of code injection attack that enables an attacker to execute malicious code on unsuspecting clients, such as a web browser.

Typically injected code is often a mix of HTML and JavaScript, which has been specifically crafted in a way to bypass application or browser defences.

Applications while fail to sanitize.

data correctly can be susceptible to attack and inadvertantly deliver malicious code to clients.

So how much damage can SSX exploit achieve?

Generally speaking, a successful attack on a victim, often means the attacker has access to the JavaScript environment.

This can lead to exploits such as browser hijacking where an attacker control and manipulate your browser session, credential phishing, where a victim's username and password is stolen, by being submitted to a fake authentication form.

Session hijacking where a victim's cookies containing unique session ID, which is stolen.

Kool-Can lead to an account being impersonated.

Data leakage where personal identifying information or PII data or other private data, concerning the user is stolen or even keystroke logging, where the victim's input in the browser session is logged and stored moderately, which can expose all sorts of data.

Despite being a well known vulnerability for many years, XSS still remains a problem today.

It's still constantly exploited in the wild due to being easy for attackers in a web application is vulnerable to attack.

As a result, a significant portion of web attacks continue to use XSS today.

The open application security project, or OWASP for short recently published a report highlighting the top 10 security risks impacting web application security.

XSS attacks have been so common that they've been featured as a major risk in every publication since 2003.

On top of that, XSS has also been ranked as the number one type of vulnerability publicly disclosed in the common vulnerabilities and exposures program, or CVE for short.

The type of attack vector that is being exploited by the XSS has also increased in recent years.

Many web applications are now using single page architecture designs and using client-facing JavaScript to render the UI.

This has led to a rise of XSS attacks that now try exploiting how the document object's model is used in applications when they render web components.

So let's have a look at some stats.

Many clients server applications critically rely on open-source packages to support key features.

In a 2020 state of open-source security report published by Snyk, cross-site scripting was the most common vulnerability disclosed and dwarfs many of the exploits as shown on this chart and in previous years as well.

This is an example using the create react app to set up a boilerplate project already introduces almost 2000 package dependencies alone.

What if just one of them introduces XSS vulnerabilities into your application?

Monitoring packages for vulnerabilities is a major challenge that needs to be.

The volume of cross site scripting attackes has also been rising steadily over the years.

The Edgecast CDN network identified that the amount of XSS attacks that the web application [?] incepted and blocked had almost doubled by the end of 2020, representing 10% of all their blocked traffic, this increasing amount of attacks only proves just how important it is to ensure that web applications are well-protected against XSS attacks.

Let's look at an interesting example.

Back in September this year, an independent security researcher, Bobby Rouch had discovered an XSS vulnerability of Apple AirTags, when they're set on lost mode.

When placed into lost mode [?] is able to prvide a phone number field for others to contact them should someone find and scan the lost tag.

Scanning the tag will then open URL associated with it, which is hosted on Apple's website.

While the vulnerability has since been fixed, it was possible for an attacker to hijack the user's browser by injecting and storing malicious JavaScript code into the phone number field.

In the example shown, if someone scans the tag using the phone and open URL in the browser JavaScript code in the phone field would actually execute.

This will then redirect them to the attackers website, which would then try and steal the user's Apple ID credentials, some pretty scary stuff.

As we've just reviewed Cross site scripting continues to be a problem after all these years, with attacks readily increasing, and becoming more innovative as demonstrated by the AirTag example, understanding how these attacks occur in the first place, it's the first step to properly defending our users.

Let's take some time now to explore just how some of these attacks are executed by an attacker and how users can fall victim to an attack without proper security controls in place.

The first type we'll be examining is this stored XSS attack, also known as the persistent XSS attack.

This attack has malicious code, like JavaScript stored in a web application, which is then injected into the servers HTTP response.

Attackers often discover unprotected forms, which failed to validate or sanitize input data and let them insert practically anything into the database.

As we demonstrated in the AirTags, exploite, these are considered the most dangerous types of XSS attacks since any user who visits the compromised website risks being exploited.

Let's take a look at an example of how a stored XSS attack works.

And attacker in this scenario will attempt to hijack a user's session by stealing their cookies on a site that they have an account with.

First an attacker discovers a vulnerability with a website that enables them to inject [?], which is JavaScript [?]. The code will then be sent with responses to all users that visit the website.

Second, a user visits, a compromised website, and an authenticated session.

Third website returns response with the malicious code injected into the HTML document body.

And lastly, once the browser has loaded the website, the malicious code then executes, reads a cookie successfully in the document and then forwards them to a site controlled by the attacker.

That's some pretty nasty stuff.

The next attack will be examining is the reflected XSS attack, also known as a non-persistent XSS attack.

This attack uses malicious JavaScript, which is injected with a HTTP request.

In the example in the table, the website exposes search functionality, sets the query parameter for the search keyword, and that can easily manipulate this URL and inject a malicious script as the keyword.

Let's assume the website is vulnerable and just displays a search keyword on a result page without any validation or filtering.

The script can then get easily inserted into the HTML document and then get executed in the web browser.

Let's take a look at another example of how reflected XSS attack works.

Once again, an attacker will attempt to hijack a user session by stealing their cookies on a site where they have an account.

First an attacker discovers a vulnerability with a website that enables them to inject JavaScript for a page's query parameter.

They send phishing emails to users containing a URL, with the malicious code appended.

Second, the user reads the email and opens a malicious link and requests a document from the website.

Third, the browser then loads the website document, hoeever the malicious card from the query parameter gets injected and executed.

Once again, the script reads the cookies that are accessible in the document and forwards them to a site controlled by the attacker.

The last attack we'll be examining is a DOM based XSS attack.

This type of attack is becoming increasingly more common with many web applications starting to render user interface on the client side.

This attack uses malicious JavaScript, which is injected through attacker controlled values, such as URL query parameters like we saw with the reflected XSS attack.

Wherethis attack differs however is malicious code is executed when an application manipulates the HTML document using the Document Object Model and has the code inadvertently injected.

Some of these attacks can also bypass server-side validation.

Client applications which use unfiltered URI fragments can potentially be exploited and have code injected onto the page.

These fragments values are never passed to the server using this example as an attack.

Let's take a look at how a DOM based attack works.

Just like the previous scenario an attacker we will attempt to hijack a user session by stealing the cookies on a ites where they have an account.

First, an attacker discovers a vulnerability with a client side application that enables them to inject JavaScript code using something like a UI fragment.

They send phishing emails to the user containing the URL with the malicious code appended.

Second, the user reads the email, and opens the malicious link and accessed the web application.

Third the web application returns a normal response, but there's no actual malicious code attached.

Fourth, the client-side application, then renders the URI based on the code received, however incorrectly processes the URL, which injects malicious code into the document.

Lastly, script then reads the cookies that are accessible in the document and forwards them to a site controlled by the attacker.

We've seen the impacts of different types of XSS attacks present and the nned to preevent them from occurring in the first place.

Let's now examine some best practices that you can adopt to help mitigate these type of attacks and protect your users from falling victim to these exploits.

One of the best ways to prevent XSS attacks is implementing robust input validation within your applications.

A good strategy is always distrust input data, no matter the source-be if from a user or external system.

By assuming that input data you receive to be malicious from internal public facing users helps you develop more strict validation rules.

So what type of rules should you consider for user inputs?

Using AllowLists is a recommended approach for defining sensible rules such as required data type, size, range or pattern defined by regular expression.

By explicitly describing what dalid data looks like you reduce the risk of malicious code being processed and stored in your application.

If your application needs to accept HTML about input, consider a sanitzer library like DOMPurify.

Sanitizing HTML will help reduce risk of XSS code getting injected.

Always make sure that you your application forces validation rules server side.

Well there are many UX benefits by having validation client's side, by notifying the user of any mistakes for an input such as entering email wrong, you cannot rely on this solely since an attacker can just bypass it completely and send the data directly to the server.

You need to validate on both stacks, which is the most beneficial outcome for the user and for validating dollar in general.

There are also many security benefits to adopting a web application firewall or a WAF for short.

Web application firewall can help protect your application from XSS and many other types of attacks.

They work by analyzing and intercepting malicious requests based on known attack patterns and blocking them before they reach a backend.

Another major way to prevent XSS attacks is ensuring your data output has always been appropriately sanitized.

You must escape any data contained within a response that may be unsafe, such as potential input that came from user.

Escaping prevents malformed HTML and JavaScript from being interpreted as code.

Unsafe values also need to be escaped differently based on the context where the value is being used.

Values being inserted into HTML should be escaped as HTML.

Values being inserted into JavaScript should be escaped as JavaScript, and so forth.

In this example, we have a paragraph element that displays someone's username from an application.

If someone was a bit mischievous, they might actually try and make that username a script tag.

Assuming this value is accepted as an input by the application, if it is properly esxcaped as an output, the script tags would not be inserted in the document and pose any risk to users.

Another point of advice is to not reinvent the wheel and use established security frameworks and sanitizer packages.

Using these tools will help ensure that you are correctly handling unsafe data without having to maintain different escaping rules for different contexts.

Using a content security policy or CSP for short is a great way to provide additional app security.

CSPs declare which resources are trusted for dynamic calls and help detect and mitigate XSS and many other different types of web attacks.

Specified as a header on a HTTP response, CSPs helps set up a resource boundary.

This helps limit which reasources are accessible dynamically in the browser context, and can prevent XSS attacks from being able to send data outside of your application, or being able to use inline scripts.

Resuorces are restricted by using policy directives using schemes, such as HTTPS or filesystem, declaring the host source, and also potentially including content hashes of those scripts and styles that you want as trusted resources.

CSPs are also capable of reporting policy violations.

The CSP-Report-Only in the header can be used to evaluate a policy and send resource violations via post request.

This enables you to test policies before enforcing them in a production environment.

Reports are also supported when a policy is actually being enforced in a production environment as well.

Let's take a look at a few CSP examples.

In the first example, we have a pretty simple policy.

Using the defaultsrc directive, we are declaring that we set all resources from self, which is an alias for the same origin of the document where the policy is associated with.

Requests for resources outside of this origin automatically fail in the browser context.

In the second example we are resticting where scripts and images can be loaded from.

Here we are specifying that the only acceptable resources are from the same origin and Google Analytics domain.

And lastly, in the last example, we have a more strict policy using a more of a white-list approach.

Here we're outright denying all resource access by default.

And then we add the exceptions for resources that we do trust such as scripts, images, fonts, style sheets, and form actions from the same origin.

Now, say you have a CSP that locks down resources correctly for an existing site or application can be a little bit of trial and error.

It is well worth the time investment however, due to the additional protection against malicious attacks it brings.

Let's take a look at how reporting works in CSP.

In this first example, we use the CSP-Report-Only header to declare a policy we should evaluate, but not enforce.

Any violation of this policy will send a post request of a JSON object, detailing any policy violations to the specified endpoint.

In the second example, shown you can also enable violation resports to be sent with a policy that's being enforced in production.

The third example shows a sample CSP policy violation report being sent to the report URI delared in the policy.

This violation report details which document raised the violation, the violated directive in the policy, and which resource is blocked.

Resports can be useful for determining when XSS attacks are occurring on your website, and should be actively monitored.

While we've only touched on some of the more common directives of CSPs they're capable of limiting XSS attacks even further.

Make sure you stay tuned for Bjarki's presentation, eliminating excesses by adopting Trusted Types, for more details on how you can reduce the risk of DOM based XSS using the Trusted Types directive in CSP.

Now let's take a look at some other HTTP security headers to help provide additional protection against cross site scripting attacks.

The Strict-Transport-Security header can be used to the force of browser to use HTTPS connections with the hosy.

Using this in conjunction with HttpOnly cookies can help provide additional protection against XSS.

So those cookies are no longer accessible by JavaScript.

X-Frame-Options header, which has been set to deny helps assisting and preventing click jacking attacks, preventing the document from being embedded in any type of frame.

X-Content-Type-Options header being set to nosniff will help prevent browsers from overriding a resource’s MIME type by inspecting the content of a resource.

This defaults to using the content type to determine the media type for the resource being loaded.

This helps prevent resources being loaded based on its contents, rather than it's actually declared media type.

The last header X-XSS-Protection is used to enable the XSS auditor, which is a built-in browser function to try and mitigate Reflected XSS attacks.

This is easy to bypass and can actually introduce cross site information links, so this should really be left, leaving this as a disabled option.

Support is also quite limited in browsers with Chrome removing support for the XSS auditor quite recently.

The CSP is the best replacement for this type of header if you want, similar protection.

It is important that you regularly test and monitor your web application for exploits, and indentify gaps within your security controls.

Manual testing, while time-intensive can be useful for assessing how effective your validation and filtering fules are for important output of data.

The OWASP cheat sheet series ais a fantastic resource which highlights many types of CSS filters which can be bypassed.

Automatic tests can also be very useful in invalidating common XSS weakneses, and making sure that they're being handled correctly, especially when maintaining any sort of large application.

Fuzz testing or fuzzing can help in this regard as it identifies bugs and gaps in validation by randomly faking invalid, unexpected, or random types of data in your inputs.

Just remember though, these types of tests can lull you into false sense of security.

So always make sure you use combination of manual and automated testing.

Some highly recommended tools that can assist with testing include the highly popular Burp suite, the growser exploitation framework and the OWASP Zed Attack Proxy.

Next it is important to review code and any packages or libraries that your website or application are using for potential XSS exploits.

Code scanningtools such as Snyk help identify potential security issues within your code base.

These types of tools can identify when inputs may not have sufficient validation or sanitization and hides the severity of such findings.

Overall, these tools are fantastic finding, many ypest of different bugs that may otherwise go unnoticed.

It's also critical for you to monitor application dependencies for any known vulnberabilities.

For NodeJS packages and npm audit can quickly help assess which packages have post-security vulnerabilities and often offer to fix them automatically, by updating package versions that resolve said vulnerabilities.

Lastly, make sure you automate scanning and monitoring into your pipelines.

Having every build or deployment check if there are any vulnerabilities in your code or packages can help you greatly and resolve any issues as they arise.

We have now explored some of the best practices that can really help eliminate cross site scripting attack vectors on your application and ultimately better particular users from falling victim to such attacks.

Now I'm going to provide you a checklist, which you and your team can use to quickly assess if you have proper protections in place to mitigate XSS attacks in web applications.

First off on the checklist is making sure that you enforce proper data validation and filtering on user inputs, denying inputs that don't meet your requirements will help reduce the amount of possible XSS attack vectors.

Second, it is critical to ensure that any user submitted content in your aplications is properly sanitized and escaped before being sent in a response to web client.

Doing so will greatly reduce the risk of XSS vulnerabilities within your application as well.

Third, using a content security policy can help set up an access boundary around your application.

Restricting which dynamic resources can be loaded can also reduce the attack vectors that a successful XSS attack can exploit.

It should be considered a last line of defense.

Fourth, make sure you setup and regularly scan and test your application for XSS vulnerabilities or any vulnerability for that matter.

Be notified and updating packages, which are out of date or susceptible to exploits will help greatly reduce the number of vulnerabilities being introduced into your application.

Lastly, the fifth point, it is really important to understand that security within your team is a shared responsibility.

The najority of XSS attacks today can often be attributed to an oversight in validating or sanitizing user input data.

It is important that everyone on your team is aware of how XSS attacks work, so that developers and testers alike are able to add and validate security controls to mitigate such attacks in the future.

Spreading awareness will help others understand how to defend and mitigate these attacks.

Use this mitigation checklist as a guide to help evaluate if you have a solid foundation for protecting your users from XSS and other attacks.

I hope this presentation provided you with more insight into how cross side scripting attacks occur and how they impact your users, how you can best defend against these attacks now,and into the future.

Thank you for watching.


Cross-site Scripting (XSS)

What is XSS?

Cross-site scripting (XSS) is a code injection attack that enables an attacker to execute malicious code on an unsuspecting web client.

Injected code is often a combination of HTML and JavaScript specifically crafted by attackers to bypass browser protections.

Web applications which incorrectly process data can be vulnerable and inadvertently deliver malicious code, which can lead to catastrophic results.

What can XSS exploit?

Some examples of what a successful XSS attack can achieve:

  • Browser hijacking
  • Credential phishing
  • Session hijacking
  • Data leakage
  • Keystroke logging

XSS still remains a problem today

Consistently exploited in the wild

  • Majority of web attacks continue to use XSS
  • Featured in every OWASP Top 10 report published since 2003
  • Most common vulnerability published in CVEs for 2020/21

Increased attack vectors

  • Growth in attacks targeting JavaScript frameworks and browser vulnerabilities

Top disclosed vulnerabilities

State of Open Source Security Report 2020-Snyk

Bar chart shows top disclosed vulnerabilities 2014-2019. XSS is most with cumulative 1042.

XSS attack volume increased in 2020

Cross-site scripting (XSS) attacks in Q4 2020: Trends and best practices-Edgecast

Chart shows more than 15 million XSS attacks in Q4 2020

Example: Apple AirTags Lost Mode vulnerable to XSS

XSS vulnerability was recently discovered for Apple AirTags when they were placed on Lost Mode.

An attacker could inject and store JavaScript code into the tag’s phone number field.

If a victim used NFC to read the tag and browse to the returned URL, their credentials could be hijacked.

<script>window.location='';var a = '';</script>

Source Zero-Day: Hijacking iCloud Credentials with Apple Airtags (Stored XSS) - Bobby Rauch, Medium

XSS Attacks

Stored XSS attack

Malicious code is injected inside the HTTP response due to being stored on the server.

These attacks often exploit unprotected web forms where input data is not properly validated and sanitised.

Considered the most dangerous type of XSS attack as any user who visits a compromised website could risk being exploited.

Stored XSS attack–session hijacking

An attacker, a website and users are arranged in an inverted triangle. An arrow connects the attacker to the website. Arrows connect the website and users to one another. An arrow connects the user to the attacker.

There are four steps in the attack

  1. Attacker injects malicious code into target website to steal user cookies
  2. User visit trusted website
  3. Website sends malicious code with HTML response
  4. Malicious code sends user session cookies to attacker

Reflected XSS attack

Malicious code is injected with a HTTP request. Typically this is performed by having code passed as a query parameter.

HTTP Request
Reflected XSS Attack<script>alert("Pwned")</script>

If the website doesn’t sanitise the query parameter correctly and renders the value, the script can execute in the web browser.

Reflected XSS attack session hijacking

Attacker, user and Website are connected making an inverted triangle. The following steps are involved in the attack.

  1. Attacker sends link containing malicious code (e.g. phishing email)
  2. User opens malicious link and requests website
  3. Browser loads trusted website and executes malicious code
  4. Malicious code sends user’s session cookie to attacker

DOM-based XSS attack

Malicious code is executed by client-side JavaScript that takes data from attacker-controlled values such as URL query parameters.

Web applications using DOM in combination with unvalidated input values can execute malicious code when rendering HTML.

These attacks can bypass server-side validation when using URI fragments (#) as they are never passed to the server.<script>alert("Pwned")</script>

DOM-based XSS attack session hijacking

Attacker, user and Web App are arranged in a row. User is between attacker and web app, with arrows connecting user to and from attacker and to and from web app. The following steps are associated with the attack.

  1. Attacker sends link containing malicious code (e.g. phishing email)
  2. User opens link and accesses web application
  3. Web application returns response without malicious code embedded
  4. Browser executes web application code however incorrectly processes URL and malicious code is injected
  5. Malicious code sends user’s session cookie to attacker

Mitigating XSS Attacks

Input validation

Distrust input data from any source

  • Assume input data could be malicious from public and private users

Enforce validation rules on any user input

  • Use allowlists to define rules for acceptable values
  • Sanitise any required HTML inputs using libraries like DOMPurify
  • Always enforce validation rules server-side

Use a Web Application Firewall (WAF)

  • Intercept malicious requests before they reach your backend

Sanitise data output

Escape response data sent to clients

  • Prevents malformed HTML and scripts being interpreted as code
  • Unsafe values must be escaped differently depending on context where it is used (e.g. HTML, Attributes, CSS, JavaScript and URLs)
<p>Hello Username!</p> // String
<p>Hello <script>alert(1)</script>!<p> // Injected script element
<p>Hello <script>alert(1)</script>!</p> // Escaped HTML

Leverage framework and sanitiser security packages

  • Use built-in security tools where possible. Don’t re-invent the wheel!

Content Security Policy (CSP)

Web standard for enforcing a trusted resource policy in web pages and applications to help detect and mitigate XSS and other attacks.

  • Setup a boundary around your application by specifying which dynamic resources are permissible in the browser context
  • Restrict resources using directives specifying schemes, hosts and content hashes
  • Report policy violations before enforcing them in production

Content Security Policy examples

Allow all resources but limit scope to same origin

Content-Security-Policy: default-src 'self';

Allow images and scripts from same origin and Google Analytics

  Content-Security-Policy: script-src 'self';
                         img-src 'self';

Disallow everything but allow scripts, images, fonts, styles and form actions from same origin

Content-Security-Policy: default-src 'none';
                         script-src 'self';
                         img-src 'self';
                         font-src 'self';
                         style-src 'self';
                         form-action 'self';

Content Security Policy reporting

Send report violations via POST without enforcing policy

Content-Security-Policy-Report-Only: <policy goes here>; report-uri /csp-reports

Enforce policy and send report violations via POST

Content-Security-Policy: <policy goes here>; report-uri /csp-reports 

Report example for policy script violation

	 "csp-report": {
	 "document-uri": "",
	 "referrer": "",
	 "blocked-uri": "",
	 "violated-directive": "script-src 'self'",
	 "original-policy": "script-src 'self'; report-uri /csp-reports"

HTTP security headers

Response headers that provide additional protection against XSS:

Force browser to use HTTPS connections with host.
X-Frame-Options: deny
Prevent clickjacking attacks by disallowing page from being embedded within frames.
X-Content-Type-Options: nosniff
Prevent browsers from content sniffing and overriding resource MIME type. Defaults to Content-Type.
X-XSS-Protection: 0
Enables XSS auditor to mitigate Reflected XSS attacks. Can introduce security issues so should be disabled and replaced with Content Security Policy.

Testing and vulnerability scanning

Regularly test your web applications for exploits

  • OWASP Cheat Sheet Series useful for manual testing
  • Automated testing useful for identifying common weaknesses
  • Recommended tools include Burp Suite, BeEF and OWASP Zap

Identify potential XSS exploits in code or packages

  • Use code scanners to inspect application code for potential exploits
  • Monitor application dependencies for known vulnerabilities
  • Automate scans with your CI/CD pipelines

XSS Mitigation Checklist

XSS mitigation checklist

  1. Enforce data validation and filtering
  2. Sanitise response values involving user data
  3. Restrict access to dynamic resources via Content Security Policy
  4. Regularly scan and test your application for vulnerabilities
  5. Build and spread awareness about XSS within your team

Thank you!