HiveBrain v1.2.0
Get Started
← Back to all entries
patternphpMinor

Preventing XSS attacks with proper escaping

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
escapingwithxssattacksproperpreventing

Problem

The following page simulates XSS attacks and successfully (?) prevents them. I want to know if I've missed any other major attack vectors (or small ones) and/or if anyone has suggestions as to improving my escaping methods.

There are three contexts in which I attack:

  • direct PHP echo into an HTML tag



  • Attack: an HTML element with an onclick



  • Solution: convert everything inside the tag into its HTML entity code



  • inside a JavaScript string



  • Attack: closing script tag followed by arbitrary code



  • Solution: escape quotes as well as forward slashes



  • setting innerHTML with JavaScript



  • Attack: an HTML element with an onclick



  • Solution: convert to HTML entities when setting innerHTML (unless it's supposed to be an element)



  • inside an onclick attribute



  • Attack: closing quote and adding another bit of code



  • Solution: convert into HTML entities



To implement the solutions detailed above, I made three functions (2 in PHP, 1 in JS):

  • escapeForJSString: escapes anything that would break out of the string, as well as forward slashes, to prevent closing script tags



  • escapeHTMLSpecialChars: a wrapper around htmlspecialchars that escapes single quotes



  • escapeForInnerHTML: basically does what htmlspecialchars does in PHP but in JS



xss-attack-prevention.php:

alert('y0uv3b33nh4ck3d');\"";
    $userInput2 = "";
    $userInput3 = "\"); alert(\"pwn3d!\\\")";
?>

XSS Attack Prevention

var n00bz = "";
var l33t = "";

")'
>Click me to see a message!

document.getElementById('div3').innerHTML = "Click me and nothing will happen!" 
    + escapeForInnerHTML(l33t);


xss-attack-prevention-helpers.php:



xss-attack-prevention-helpers.js:

```
function getType(val) { return Object.prototype.toString.call(val).slice(8, -1).toLowerCase(); }
function isString(val) { return getType(val) === "string"; }
function isArray(val) { return getType(val) === "array"; }
// returns false on unexpected input
// input must be
// - text : a string
// - repl

Solution

There are already native functions to escape for HTML and JS strings: htmlspecialchars() and json_encode(). See this related question on Stack Overflow

As for innerHTML, simply don't use it. Use textContent instead. If you wish to allow for formatting (for example, in comments or posts), I recommend Markdown

Context

StackExchange Code Review Q#71277, answer score: 2

Revisions (0)

No revisions yet.