What are the XSS best practises to prevent attacks?
Since you want current XSS best practises and the latest answer here is August 2012, I thought I might as well weigh in and update this. Best practices to prevent any type of XSS attack (persistent, reflected, DOM, whatever). Strictly validate all input. For example, if you're asking for a UK postcode ensure that only letters, numbers and the space character is allowed. Do this server-side and if validation fails, display a message to the user so that they can correct their input. Do this for all variables outside of your control, including query string, POST data, headers and cookies.
Add yourself some security headers. Namely
X-XSS-Protection: 1; mode=block to activate reflective XSS browser protection into blocking mode instead of filtering mode. Blocking mode stops attacks like this. Edit 2021-01-28: This header is now deprecated due to browsers like Chrome discontinuing their inclusion of XSS auditors.
X-Content-Type-Options: nosniff to prevent JavaScript being inserted into images and other content types. Content-Security-Policy: with strict script-src and style-src's at least. Do not allow unsafe-inline or unsafe-eval. This is the daddy of headers for killing off XSS.Follow the rules in the OWASP XSS (Cross Site Scripting) Prevention Cheat Sheet when outputting values, however for rule #3 I'd do the following instead: Use HTML data attributes to output anything dynamic on the page.
e.g.
Where @foo will output an HTML encoded version of the variable. e.g. " /> would give
Grab these values out using JQuery or JavaScript: var foo = $("body").data("foo");
This way you don't need to worry about any double encoding, unless your JavaScript later inserts as HTML, however things are still simpler as you deal with the encoding there too instead of mixing it all together.
Use a function like below to HTML encode if you're using document.write, otherwise you could introduce a vulnerability. Ideally though use textContent or JQuery's text() and attr() functions.
Tackle these in reverse order. Concentrate on #3 as this is the primary mitigation for XSS, #2 tells the browser not to execute anything that slips through and #1 is a good defence-in-depth measure (if special characters can't get in, they can't get out). However, #1 is weaker because not all fields can be strictly validated and it can impair functionality (imagine Stack Exchange without the ability to allow "" as an input).
function escapeHtml(str) {
return String(str)
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'")
.replace(///g, "/")
}