Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Stopping typed text running as code (XSS)

After this lesson: I can stop a page from running text that a visitor typed.

55 min lesson3 commandsDVWA lab: practise SQL injection and XSS on the Damn Vulnerable Web Application

A guestbook that runs its visitors' notes

A shop adds a guestbook to its site. Visitors leave a note and everyone reads the notes on one page.

One visitor writes a note that is not words but a tiny program. Every later visitor opens the page and their browser quietly runs it. The shop wrote none of it.

The one rule

Warning

This lab is a website that is insecure on purpose. Attack your own private copy and nothing else. It has no way out to the internet. Never try these things on a site that is not yours: in the UK that is a crime under the Computer Misuse Act 1990.

By the end of this lesson

Note

I can stop a page from running text that a visitor typed.

Key words

WordWhat it meansExample
Cross-site scriptinga page that runs script a visitor typedXSS
Scripta small program that a browser runs inside a page
Escapeswap special characters for safe text< becomes &lt;
Reflectedsent in a request and shown straight back in the reply
Storedsaved by the site and shown to every later visitor
Cookiea small value the browser keeps and sends back to the site

The cells students fill in are left blank in this preview.

Typed text can become part of the page

A browser reads a page as text with tags in it. A <b> tag makes bold. A <script> tag runs a program.

If a site puts a visitor's text into the page unchanged, the browser cannot tell typed text from the site's own tags. Script a visitor typed then runs as if the site had written it.

Worked example: reflected and stored

ReflectedStored
Where the text goesIn the request, then straight back in the replyInto the site's records, then into later pages
Who is hitThe person who opens the crafted linkEveryone who opens the page afterwards
ExampleA search page that says: you searched for ...A guestbook or a product review
Why stored is worseOne note reaches many visitors with no link to send

The cells students fill in are left blank in this preview.

Look at the website in your lab

Your lab runs the website you will test. Start it, then run these three. They only look at the sign-in page. They do not sign in and they type no script.

The cookie matters here. A script that runs in a page can read the page's cookies, unless the cookie is marked HttpOnly.

Is the website up?

Command
curl -s -o /dev/null -w "%{http_code}\n" http://dvwa/login.php

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

The cookies the site sets

Command
curl -s -I http://dvwa/login.php | grep -i "^set-cookie"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

How many cookies say HttpOnly?

Command
curl -s -I http://dvwa/login.php | grep -ic httponly

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

What the three answers tell you

The first prints 200. The second prints two lines, one for a cookie called security and one for PHPSESSID, which is the session. The third prints 0.

No cookie says HttpOnly. So script that ran in a page here could read the session cookie. That is why XSS often leads to stolen sessions.

Escaping turns special characters into text

The fix is to escape a visitor's text on its way into a page. < becomes &lt; and > becomes &gt;. The browser draws them as the same characters but never reads them as a tag.

Replace & first. If you replace it last, you turn the & in &lt; into &amp; and the text comes out wrong.

An escape function

Code: python
def escape(text):
    text = text.replace("&", "&amp;")
    text = text.replace("<", "&lt;")
    text = text.replace(">", "&gt;")
    return text

# Change the note and press Run. Then move the & line to the end and run again.
note = "Great bread <b>and</b> cakes & tea"
print("<p>" + escape(note) + "</p>")

A common mistake

Warning

Many people think it is enough to block the word script when a note is saved. It is not. Tags like img carry script too, and filters miss spellings. Escape at the moment you write the text into a page, for every value, and then the question never arises.

Escape on output, and add layers

Escape when you write text into a page, not when you save it. The same text may later go to a page, an email or a file, and each needs its own escaping.

Add layers behind it. Mark session cookies HttpOnly. Send a Content-Security-Policy header that limits which scripts may run. These limit the damage if one escape is missed.

About this lab and its source: DVWA lab: practise SQL injection and XSS on the Damn Vulnerable Web Application

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.