Sunday, March 5, 2017

How can PHP json_encode prevent XSS (Cross-Site Scripting) attacks?

Cross-Site Scripting attack (also known as XSS attack) is a technique that can be used by a malicious script, to perform actions in a website as if the user were performing them.

Lets say a server is answering to http://www.website1.com?some_number=1, assigning the value of the get parameter some_number to a variable $variable. Somewhere in the response the following script is used to render the page:
<script>
    var data = {
        param: <?php echo $variable ?>
    };
</script>

An attacker using a different site (http://www.website2.com) could have a script that, without the user's consent, makes a request to http://www.website1.com?param='||alert('hello')||'1.

This means that the attacker could run any script inside the domain www.website1.com, as if it was the user. If website1 is an online shop for example, and the user is logged in, it would be possible to place an order in the name of the user.

One simple way of preventing such kind of attack for this particular situation is to use PHP json_encode. The code could be replaced by this:
<script>
    var data = <?php
        echo json_encode([
            'param' => $variable
        ])
    ?>;
</script>

It is interesting to note that using json_encode also prevents the contents of the variable from breaking your HTML structure. For example, if the value of $variable is '</script><div>hello</div>', with the first code, PHP would render the following output:
<script>
    var data = {
        param: </script><div>hello</div>
    };
</script>

This results in a JavaScript syntax error, and a malformed HTML document.

When using json_encode, PHP automatically escapes the character '/', and that makes the browser interpret the data as a JavaScript string:
<script>
    var data = {"param":"<\/script><div>hello<\/div>"};
</script>

So, besides making the code look better in some cases, using json_encode can prevent some XSS attacks, and prevent your HTML code from being corrupted.