4

I'm currently testing my own XSS filter and don't know if I thought everything through, so I need some advice.

Let's say my code looks like this:

<script>
var test = {src: "test", layer: {"input": "USER INPUT", "event": "ready"}};
</script>

In this specific case, if I replace \ with \\ and " with \" is it possible to trick my filter? Of course the user input would be where USER INPUT is in my code.

Evo_x
  • 143
  • 1
  • 5

1 Answers1

9

In this specific case, if I replace \ with \\ and " with \" is it possible to trick my filter?

That's not sufficient, your filter is insecure.

E.g., one valid XSS attack vector would be </script><svg onload=alert(1)>, ending up with:

<script>
var test = {src: "test", layer: {"input": "</script><svg onload=alert(1)>", "event": "ready"}};
</script>

Since the XML (HTML) tree is parsed before any JS is evaluated, the closing script tag (</script>) will terminate the script despite being placed within a JS string.

Another problem with your filter are line breaks. If an attacker can insert a 0x0a byte, they can break your script by causing a syntax error (since a double quoted string can't span multiple lines):

<script>
var test = {src: "test", layer: {"input": "
", "event": "ready"}};
</script>

If you're using PHP, a convenient filter function to work safely with user input inside JS is json_encode(). From this answer:

With plain PHP a common and safe approach is to use json_encode() as explained here. E.g.:

var foo = <?php echo json_encode($foo, JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS); ?>

json_encode() returns the JSON representation of a value, hence it's guaranteed to evaulate to a valid object in your JS code and you can just assign it to a variable as shown. But don't omit the additional flags. Depending on the context, an attacker could otherwise use payloads like </script> to break out of the entire script tag.

Arminius
  • 43,922
  • 13
  • 140
  • 136
  • 1
    Does json_encode escape though? – user253751 Oct 10 '17 at 19:55
  • 1
    @immibis Yes, with the correct flags! (That's why I linked [this answer](https://security.stackexchange.com/questions/110101/proper-way-to-protect-against-xss-when-output-is-directly-into-js-not-html/110110#110110) that addresses this aspect.) – Arminius Oct 10 '17 at 20:02
  • Alternatively, it maybe be useful to use `<![CDATA[` tags instead of trying to escape your json. – Matthew Oct 10 '17 at 20:27
  • 1
    @Matthew how does that help? – user253751 Oct 10 '17 at 20:34
  • `"}; /*]]>*/ ` works just fine, the entire contents of the script tag are treated as character data instead of html. `alert(json["myvalue"]);` will now popup with `` – Matthew Oct 10 '17 at 20:40
  • @Matthew An attacker can just terminate the CDATA section. – Arminius Oct 10 '17 at 20:43
  • That is correct, all you need to do is escape CDATA within your content block (https://stackoverflow.com/questions/223652/is-there-a-way-to-escape-a-cdata-end-token-in-xml) and that will work for any content that you want to be treated as character content, regardless of the underlying content, be it json, xml, etc. – Matthew Oct 10 '17 at 20:45
  • @Matthew: cdata? that would only affect xhtml pages, haven't seen any of those in a while... – dandavis Oct 11 '17 at 10:57