Preventing JavaScript execution with JavaScript?
The idea is to provide a fallback that prevents (inline) JavaScript for browsers that do not support CSP.
Bear in mind that CSP is not to be used as a first line of defense. You should properly encode per context to prevent XSS in your application. OWSAP has good information on this.
That being said, CSP can be a good fallback to make XSS much less serious, should an XSS vulnerability (i.e. wrong or no encoding somewhere on your page) be found in your application and exploited.
I know that it is possible to overwrite existing functions, but it's not clear to me how exactly this would work.
It is very easy to do. For example, XMLHttpRequest = myFunction
, or XMLHttpRequest = null
would prevent scripts from using XMLHttpRequest
directly.
The problem is that if an attacker may not be using that particular function, and if the attacker knows you are doing this, he could easily use an alternative method. While it might be possible to overwrite all functions, it is not recommended as a reliable solution.
Is there a trivial solution that 100% prevents any further script execution?
If you have a syntax error in your <script>
, then nothing in that <script>...</script>
will run. Unfortunately, with XSS, the attacker could easily start a new <script>
that would work just fine.
Also there are many many ways to inject JavaScript besides <script>
, for example <img onload>
or onerror
.
To my knowledge you cannot reliably stop all following HTML from containing XSS execution.
If not, are there solutions that work in most contexts or for most browsers (and ways to bypass them for other contexts/browsers)?
CSP version 1 browser support is starting to get good, and since CSP was designed as a backup anyway (not a first line of defense) you may be able to stop your search there knowing that browser support will be a shrinking problem.
That being said, I think the idea of overwriting functions could go a long way towards success. It seems like that could work reliably in theory. While this is not recommended, I think it would be an interesting study. I wonder how complex it would be to implement.
Is there a trivial solution that 100% prevents any further script execution?
No, I don't think so. Every script tag runs on it's own, so throwing an error would not stop the next script. alert
and company and perhaps syncronous AJAX come to mind to prevent further scripts from running, but that will lock up the whole browser.
If not, are there solutions that work in most contexts or for most browsers (and ways to bypass them for other contexts/browsers)?
Well, you could try nulling out all the global variables by looping over the properties of window. Then in theory the scripts would not have access to the DOM to do anything. In practice, this probably won't work well as not all of these properties are writable. I'm doubtful it would be possible to remove everything of interest.
Other possible hacks might be to try to destroy the document before other scripts can run, perhaps by using document.write
somehow. This would be in the land of undefined behavior and dragons.
Code Sample:
Everyone loves a good code sample, so here an example payload I imagine being tough to beat.
<iframe name="iwin"></iframe>
<script>
(function() {
// Due to the name attribute on the iframe, iwin is now
// an implicit global for the iframe's contentWindow.
// It should not have been there before the tag was parsed,
// and the name could be randomized.
// For legacy IE, to make globals accessible (0_o).
iwin.execScript && iwin.execScript();
// PWND, we have new globals.
var XMLHttpRequest = iwin.XMLHttpRequest;
})();
</script>
I wrote that comment with jQuery in mind, since it's really easy to accidentally break. Since most complicated client-side code (the kind with vectors) uses jQuery, common ajax and templates that cause vulnerabilities simply won't run without it.
JavaScript's security model is reference-based, which means if you can't reach something, it doesn't exist to the code. There are a couple un-expected refs like constructor.constructor("alert(666)")()
, but they are manageable because JS simply doesn't have that many built-ins to offer (compared to php or .net's lib). If you can conceal or destroy the reference, you remove the capability. Doug Crockford talks a lot about this, and in "use strict"
mode, it's even more enforceable on a granular level.
You would be best-off redirecting to a page without script tags; a non-js or "lofi" version, if available.
You can use a 100% sized iframe with a
sandbox
attrib to re-serve the page without script; something i have a bookmarklet for to use for compat testing (just makes a new iframe, sizes it, and set the.src
tolocation.href
). Not all browsers supportsandbox
, so you might be robbing peter to pay paul if your goal is to curtail some-how overlooked XSS.window.stop()
works in some browsers (FF for sure), and it's simple enough to use to stop the page loading in-place."burn them all"; clobber all the built-in global properties, leaving only the pure logic capabilities of the language behind. The downside is that
document
isn't modifiable, which is all a clever adversary really needs. There may be an easy way to breakdocument
, but it's a huge vector as-is.