https://google.com, then when a user loads
https://google.com or steal any user secrets associated with Google and send them back to the attacker.
There are two main categories of XSS attacks: stored XSS and reflected XSS.
A classic example of stored XSS is a Facebook post. When a user makes a Facebook post, the contents of the post are stored on Facebook’s servers, so that other users can load their friends’ posts. If Facebook doesn’t properly check user inputs, an attacker could make a post that says
This post is now stored in Facebook’s servers. If another user loads the attacker’s posts, they will receive an HTML page with this script on it, and the browser will run the script and trigger a pop-up that says
In a reflected XSS attack, the attacker finds a vulnerable webpage where the server receives user input in an HTTP request and displays the user input in the response.
A classic example of reflected XSS is a Google search. When you make an HTTP GET request for a Google search, such as
https://www.google.com/search?&q=cs161, the returned webpage with search results will include something like
You searched for: cs161
If Google does not properly check user input, an attacker could create a malicious URL
https://www.google.com/search?&q=<script>alert("XSS attack!")</script>. When the victim loads this URL, Google will return
You searched for: <script>alert("XSS attack!")</script>
The victim’s browser will run the script and trigger a pop-up that says
Just like SQL input escaping, sanitizing potentially dangerous input can be very tricky. For example, consider an escaper that searches for all instances of
</script> and removes them. An attacker could provide this malicious input:
After the escaper removes the two
<script> tags it sees, the result is
Another way to escape input is to replace potentially dangerous characters with their HTML encoding. For example, the less than (
<) and greater than (
>) signs are encoded as
>, respectively. These encodings cause less than and greater than signs to display on the webpage, without being interpreted as HTML.
Fortunately, there is a standardized set of sanitizations that is known to be robust.
Another XSS defense is using a content security policy (CSP) that specifies a list of allowed domains where scripts can be loaded from. For example,
cs161.org might allow scripts that are loaded from
*.google.com and disallow all other scripts, including any inline scripts that are injected by the attacker.
CSPs are defined by a web server and enforced by a browser. In the HTTP response, the server attaches a
Content-Security-Policy header, and the browser checks any scripts against the header.
If you enable CSP, you can no longer run any scripts that are embedded directly in the HTML document. You can only load external scripts specified by the
script tag and an external URL. These scripts can only be fetched from the sites specified in the CSP. This prevents an attacker from directly injecting scripts into an HTML document or modifying the HTML document to fetch scripts from the attacker’s domain.
Further reading: OWASP Cheat Sheet on XSS