Skip to content

Intermediate · Backend security · topic 38 of 54 · 30 min

XSS and CSRF: attacks through the browser

Explanation

XSS (cross-site scripting) is when an attacker gets their own JavaScript to run on your website, inside other users' browsers. CSRF (cross-site request forgery) is when another website tricks a logged-in user's browser into sending a request to your site. You stop XSS by escaping output and using a Content-Security-Policy, and CSRF with SameSite cookies, CSRF tokens and Origin checks.

XSS: someone else's script on your page

A script is a piece of JavaScript code. XSS happens when your page shows user text as HTML, and that text contains a <script> tag or similar. The browser cannot tell your code from the attacker's, so it runs it. The script can read the page, steal data, or send requests as the user.

  • Stored XSS: the attacker saves the script in your database, for example in a product review. Every visitor who opens that page runs it.
  • Reflected XSS: the script is in a link, like /search?q=<script>...</script>. The page repeats the search word back, so whoever clicks the link runs it.
Think of it like this: Imagine a notice board in a college where anyone can pin a note, and a helper reads every note aloud as an order: "Everyone, hand your ID card to the person at the door". XSS is like that: the page treats a visitor's note as an instruction instead of just text to display.

Stop XSS: escape output

Escaping means turning special characters into safe codes so the browser shows them as text. For example < becomes &lt; . The browser then displays a < sign instead of starting a tag.

CharacterEscaped asWhy
&&amp;Starts an escape code itself, so it must be done first
<&lt;Starts a tag
>&gt;Ends a tag
"&quot;Ends an attribute value
'&#39;Ends an attribute value
javascript
// UNSAFE: user text is read as HTML
results.innerHTML = '<p>You searched for ' + query + '</p>';

// SAFE: user text is set as plain text
const p = document.createElement('p');
p.textContent = 'You searched for ' + query;
results.append(p);
In the browser, use textContent for user data, not innerHTML (runs in a web browser).

Template engines and frameworks like React escape text by default, which removes most XSS. The danger comes back when you switch it off, for example with dangerouslySetInnerHTML in React or a "raw" filter in a template. If you must show user HTML (like a rich-text blog post), clean it with a sanitiser library such as DOMPurify.

Two more layers help. A Content-Security-Policy (CSP) header tells the browser which places scripts may load from, so injected inline scripts are blocked. An HttpOnly cookie cannot be read by JavaScript at all, so even if XSS happens, the session cookie cannot be stolen.

output
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'
Set-Cookie: sid=8f2c...; HttpOnly; Secure; SameSite=Lax; Path=/
A strict CSP header and a well-protected session cookie.

CSRF: a forged request with your cookie

Browsers send your cookies with every request to a site, even if the request starts on another site. CSRF uses this. You are logged in to your bank. You open a bad page in another tab. That page has a hidden form that posts "transfer 50,000 to the attacker" to the bank. Your browser adds your bank cookie, and the bank thinks you sent it.

html
<!-- on the attacker's site -->
<form action="https://bank.example.in/transfer" method="POST">
  <input type="hidden" name="to" value="attacker-account">
  <input type="hidden" name="amount" value="50000">
</form>
<script>document.forms[0].submit();</script>
A CSRF attack page: it submits a form to another site as soon as it opens.

Stop CSRF: three layers

  1. SameSite cookies: set SameSite=Lax (or Strict) on the session cookie. The browser then does not send it on cross-site POST requests. Modern browsers treat cookies as Lax by default, but set it yourself.
  2. CSRF tokens: the server puts a random secret token in the session and in each form. On every POST, PUT, PATCH or DELETE it checks that the token sent matches the one in the session. The attacker's page cannot know it.
  3. Check Origin: browsers send an Origin header saying which site started the request. Reject state-changing requests whose Origin is not your own site.
Tip: GET requests should never change data. Then you only need CSRF checks on POST, PUT, PATCH and DELETE.
Careful: CORS settings do not stop CSRF. CORS controls whether another site can READ your response; a forged form post still reaches your server. Use SameSite, tokens and Origin checks.

Watch the lesson

XSS and CSRF: attacks through the browser · 1/7

XSS CSRF

Two attacks use the browser against your users: XSS and CSRF.

Prefer a video by a teacher? Find free videos on “xss and csrf explained for beginners” on YouTube ↗

In real life: A review that stole sessions

A food delivery app let users write restaurant reviews and showed them with innerHTML. One user wrote a review containing a script that sent document.cookie to their own server. Everyone who opened that restaurant page leaked their session (stored XSS). The team fixed it in three ways: they showed reviews with textContent, made the session cookie HttpOnly so scripts cannot read it, and added a Content-Security-Policy that blocks inline scripts. They also added SameSite=Lax and CSRF tokens to the "change address" form.

Practice (0/2 done)

Task 1 · Code · Javascript

Write escapeHtml(text) that replaces & with &amp;, < with &lt;, > with &gt;, " with &quot; and ' with &#39;. Replace & first, so you do not escape your own escape codes twice.

Task 2 · Code · Javascript

Write checkCsrf(request, session). Return true for GET, HEAD and OPTIONS. For any other method return true only if request.headers.origin equals ALLOWED_ORIGIN AND request.headers["x-csrf-token"] equals session.csrfToken (and that token is not empty). Otherwise return false.

Quick quiz

Question 1

1.What is XSS?

Question 2

2.A script hidden in a product review runs for every visitor. What type is this?

Question 3

3.Which cookie setting stops JavaScript from reading the session cookie?

Question 4

4.In a CSRF attack, what does the attacker use?

Question 5

5.Which of these does NOT protect against CSRF?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: SQL injection and how to stop it