Created
August 24, 2012 17:52
-
-
Save tecywiz121/3453443 to your computer and use it in GitHub Desktop.
Mitigate XSS client side
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* A proof of concept client-side XSS mitigation library with minimal server side requirements. | |
* | |
* Installation: | |
* | |
* Insert this script immediately following the opening tag of the body element. | |
* | |
* Strip every instance of </noscript> and </iframe> before the output leaves | |
* your server. | |
*/ | |
(function () { | |
var userAgent = navigator.userAgent.toLowerCase(); | |
// Figure out what browser is being used | |
var browser = { | |
version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1], | |
safari: /webkit/.test(userAgent), | |
opera: /opera/.test(userAgent), | |
msie: (/msie/.test(userAgent)) && (!/opera/.test( userAgent )), | |
mozilla: (/mozilla/.test(userAgent)) && (!/(compatible|webkit)/.test(userAgent)) | |
}; | |
// Remove the body from the DOM so scripts don't execute as they load | |
var parent = document.body.parentNode, | |
body = document.body, | |
wrapper; | |
// Write a tag to stop the browser from even parsing the rest of | |
// the document. | |
if (browser.msie) { | |
// Internet Explorer doesn't support reading the contents of noscript | |
// tags, so we use an iframe with javascript disabled instead. | |
document.write('<iframe sandbox security="restricted">') | |
wrapper = 'iframe'; | |
} else { | |
// Write the wrapper tag! | |
document.write('<noscript>'); | |
wrapper = 'noscript'; | |
// Pull the body tag out of the dom just in case | |
// (IE doesn't allow this kind of modification) | |
body = document.body.parentNode.removeChild(document.body); | |
} | |
var shouldRemove = function(name, value) { | |
name = name.toLowerCase(); | |
value = value.toLowerCase(); | |
// TODO: Whitelist url schemes to only a handfull, like http, https, ftp, mailto, etc | |
return name === 'style' || name.substr(0, 2) === 'on' || value.substr(0, 11) === 'javascript:'; | |
}; | |
var callback = function (e) { | |
var noscript = body.getElementsByTagName(wrapper), | |
elements, | |
scripts, | |
attributes, | |
ii, | |
jj, | |
old_body = body; | |
if (noscript.length === 0) { | |
setTimeout(callback, 0); | |
return; | |
} | |
noscript = noscript[0]; | |
// Build the new body element from the contents of the noscript tag | |
if (browser.msie) { | |
body = document.body; | |
} else { | |
body = document.createElement('body'); | |
} | |
if (typeof(noscript.textContent) !== 'undefined') { | |
body.innerHTML = noscript.textContent; | |
} else if(typeof(noscript.innerText) != 'undefined') { | |
body.innerHTML = noscript.innerHTML; | |
} else { | |
alert('Unable to unescape contents, sorry...'); | |
return; | |
} | |
// Remove events inside the body | |
elements = body.querySelectorAll('*'); | |
for (ii = 0; ii < elements.length; ii += 1) { | |
attributes = elements[ii].attributes; | |
for (jj = 0; jj < attributes.length; jj += 1) { | |
if (shouldRemove(attributes[jj].nodeName, attributes[jj].value)) { | |
elements[ii].removeAttribute(attributes[jj].nodeName); | |
} | |
} | |
} | |
// Remove script tags inside the body. | |
scripts = body.querySelectorAll('script, object, embed, style, link'); | |
for (ii = scripts.length-1; ii >= 0; ii -= 1) { | |
scripts[ii].parentNode.removeChild(scripts[ii]); | |
} | |
if (!browser.msie) { | |
// Reinsert the body into the document after it's been cleaned | |
parent.appendChild(body); | |
} | |
}; | |
if (browser.msie) { | |
if (window.onload) { | |
window.onload = (function (old_func) { | |
return function (e) { | |
callback(e); | |
old_func(e); | |
}; | |
}(window.onload)); | |
} else { | |
window.onload = callback; | |
} | |
} else { | |
document.addEventListener('DOMContentLoaded', callback, false); | |
} | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment