1

I'm having an exercise to patch an older version of my work from university's e-class. It's written in PHP and requires version 5.3.27. One of the things I want to patch is to prevent XSS. The site uses an old editor (xinha) which supports HTML input without any validation, so XSS is extremely easy to do.

I am not allowed to change the editor so I intend to change the server side validation before using/storing the user input to block event functions (like onerror, onmouseover etc.) and JavaScript. After quite some researches I didn't find any (foolproof) way to filter out JavaScript from HTML. Blocking HTML special characters wont work for me because it will break the HTML tags. Any ideas?

7
  • There are many XSS Cheatsheets (including one from OWASP) that provide methods to do what you're asking. There is no "foolproof" way to do it, that's why people use script-blockers.
    – schroeder
    Commented Apr 16, 2017 at 11:28
  • 1
    Which programming language or web platform are you using?
    – Sjoerd
    Commented Apr 16, 2017 at 11:39
  • I have read many of them already but nothing seemed to help me without breaking the html. Except from htmlpurifier which i also dont think im allowed to use. Do you have any suggestions? Either where to search or what to search for.
    – George Sp
    Commented Apr 16, 2017 at 11:46
  • @Sjoerd it uses php and only supports 5.3.27 and mysql 4.1.22. It also requires short_open_tag, register_globals and magic_quotes_gpc to be on
    – George Sp
    Commented Apr 16, 2017 at 11:59
  • 2
    There are several tools and libraries which help you to sanitize html. But this looks for me more like a programming question (off-topic, also the programming language is unknown) or a question for a tool or library (off-topic too, also environment unknown). Commented Apr 16, 2017 at 15:47

3 Answers 3

1

Filtering out JavaScript from HTML is a very complicated thing to do, especially if you cant restrict the allowed tags and attributes to a small set (or, preferably, none). To get this right is suprisingly complicated and there are many pitfalls. One mistake is all it takes to be vulnerable.

So don't go about this on your own. Use an existing, tried and tested library. For PHP HTML Purifier is a popular one, but I am sure there are more options out there.

In addition, you should use a restrictive content security policy if possible. But don't rely on that as your only line of defence.

1

If you must allow HTML, use something tried and tested such as Google Caja to sanitize it before allowing it to output to your page.

Note that all sanitizers will likely have some undiscovered vulnerabilities. e.g. HTML Purifier has had these in the past, and Google Caja has too, therefore this is not a solid solution and you will need to regularly update your chosen library to mitigate this risk.

Rolling your own solution would be fraught with much greater risk. Also make sure you deploy a strong Content Security Policy that prevents unsafe-inline and that you only whitelist sources that will not contain anything that could make your site vulnerable (even Google CDN contains old, vulnerable versions of JQuery):

https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js
8
  • A CSP with a reporting URL would have been my first option for protection. Since the OP mentions PHP, strip_tags() would have been number 2 on the list. Using a third party tool in addition to these might help - but not something which validates on the client.
    – symcbean
    Commented Apr 18, 2017 at 12:37
  • @symcbean strip_tags() won't work against event handlers added to allowable tags (e.g. <img onload="alert(...). It doesn't matter where it validates it, as long as it is on output not on input. That is, as long as the attacker cannot bypass it. Commented Apr 18, 2017 at 13:40
  • Nor will javascript in a browser - it just cuts down on the noise. The point I was making is that an effective CSP with a reporting URL is the most effective tool, and doesn't increase the attack surface.
    – symcbean
    Commented Apr 18, 2017 at 15:46
  • Note that the reporting URL is really for debugging, not for security. Any attacker worth their salt will block requests to the reporting URL while testing any exploits. Commented Apr 18, 2017 at 16:20
  • I'm sure they will block them while testing their exploits - but it would be rather hard for them to block their victim's access after releasing the exploit. That's why the reporting URL is not for debugging but part of the active defences for a site.
    – symcbean
    Commented Apr 18, 2017 at 16:48
0

If you only need to display the HTML string without the possibility of triggering XSS:

<?php
    $yourSuspectString = "<span style=\"color:red;\" onmouseover=\"alert('Hacked!');\">This is coloured red!</span>";            
?>
<!DOCTYPE html>
<script>
/**
 * The height of the document element grows to fill the space it's allocated.
 * To find the actual height of the content, we need the height of the body plus any margins set.
 * @param iFrameDocument The Document element from the iFrame.
 */
function getRealDocumentHeight(iFrameDocument) {
    const body = iFrameDocument.body;
    // Make sure margins of items inside the body make the body larger, not the HTML element
    body.style.display = "flow-root";
    const bodyStyle = window.getComputedStyle(body);
    const topMargin = parseFloat(bodyStyle.marginTop);
    const bottomMargin = parseFloat(bodyStyle.marginBottom);
    // Add one to account for possible sub-pixel rounding down
    return body.scrollHeight + topMargin + bottomMargin + 1;
}
</script>
<iframe srcdoc="<?php echo htmlspecialchars($yourSuspectString) ?>" sandbox="allow-same-origin" style="width:100%;border:none;" onload="this.height=getRealDocumentHeight(this.contentDocument);"></iframe>

The sandbox attribute will prevent JavaScript from running inside the iFrame. All browsers that don't support sandbox don't support srddoc either. (allow-same-origin is needed otherwise contentDocument is null).

Though of course this won't prevent, say, someone embedding an inappropriate video or GIF.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .