as it isn't really popular to use Origin / X-Frame-Options http header and I don't think the new CSP in Firefox would be better (overhead, complicate, etc.) I want to make a proposal for a new JavaScript / ECMA version.
But first I publish the idea so you can say if its bad. I call it simple jsPolicy:
Everyone who uses JavaScript has placed scripts in his html head. So why don't we use them to add our policies there to control all following scripts. example:
<html>
<head>
<title>Example</title>
<script>
window.policy.inner = ["\nfunction foo(bar) {\n return bar;\n}\n", "foo(this);"];
</script>
</head>
<body>
<script>
function foo(bar) {
return bar;
}
</script>
<a href="#" onclick="foo(this);">Click Me</a>
<script>
alert('XSS');
</script>
</body>
</html>
Now the browser compares the <scripts>.innerHTML and the onclick.value with the ones in the policy and so the last script element block is not executed (ignored).
Of course it won't be useful to double all the inline code, so we use checksums instead. example:
crc32("\nfunction foo(bar) {\n return bar;\n}\n");
results "1077388790"
And now the full example:
if (typeof window.policy != 'undefined') {
window.policy.inner = ["1077388790", "2501246156"];
window.policy.url = ["http://code.jquery.com/jquery*.js","http://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"];
window.policy.relative = ["js/*.js"];
window.policy.report = ["api/xssreport.php"];
}
The browser only needs to compare if the checksum of an inline script is set in the policy.inner or if the script.src URL fits to the policy.url.
Note: The idea behind policy.relative is to allow local scripts only:
window.policy.url = false;
window.policy.relative = ["js/*.js"];
Note: policy.report should be nearly the same as done with CSP (sends blocked scripts and urls to an api):
https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-unofficial-draft-20110315.html#violation-report-syntax
Important:
- The policy can't be set twice (else it throws a warning) = constant
- To think about: The policy can only be set in the head (else it throws a warning)
- The policy is only used to check the scripts that are part of the html source and not those that are placed on-the-fly. example:
document.write('<script src="http://code.jquery.com/jquery-1.5.2.min.js"></scr' + 'ipt>');
You don't need a policy.url definition for "http://code.jquery.com..." as the policy.inner checksum validated the complete script source. This means the source is loaded even if policy.url is set to false (yes it's still secure!). This garantuees a simple usage of the policy. - if one of the policies is missing there is no limitation. This means that an empty policy.relative results that all local files are allowed. This guarantees backward compatibility
- if one of the policies is set to "false" no usage is allowed (default is true). example:
policy.inner = false;
This disallows any inline scripting - The policy only ignores disallowed scripts and throws a warning to the console (an error would stop the execution of allowed scripts and this isn't needed)
I think this would make XSS impossible and instead of CSP it would avoid persistent XSS as well (as long nobody overwrites the Policy) and it would be much easier to update.
What do you think?
EDIT:
Here is an example made in Javascript:
http://www.programmierer-forum.de/php/js-policy-against-xss.php
Of course we can't control the script execution, but it shows how it could work if a jsPolicy compatible browser would.
EDIT2:
Don't think I'm talking about coding a little javascript function to detect xss!! My jsPolicy idea has to be part of a new JavaScript engine. You can compare it to a php-setting placed into the .htaccess file. You can not change this setting in runtime. The same requirements apply to jsPolicy. You can call it a global setting
.
jsPolicy in short words:
HTML parser -> send scripts to JavaScript Engine -> compare with jsPolicy -> is allowed?
A) yes, execution through JavaScript Engine
B) no, ignored and send report to webmaster
EDIT3:
Referenced to Mike's comment this would be a possible setting, too:
window.policy.eval = false;