This is the second of my three ideas for the client-side mitigation of Cross-Site Scripting (XSS). It’s based on the same principle – that of the site owner specifying which scripts should be permitted and which not – but takes a slightly different approach.
Basically, the idea is that an HTTP header, Script-Key, defines a random string or “key” and only script labelled in some way with that string is allowed to execute. As the string will be different for every page load, injected script would not be correctly labelled and therefore would not be permitted to run.
The trick is trying to label the script in a way which allows the resulting markup to still validate. Having analysed the legal attributes of the <script> tag, here’s my current idea:
Content-Type: text/html Script-Key: D3FC219A
Of course, that could also be a <script type=”…” src=”…”>.
That’s all very well, but how do you label e.g. script in event handler attributes like “onchange”? One idea would be just to say “you don’t”, and encourage use of proper DOM methods to add event handlers. Another would be to do something hacky like saying as long as the text of the script contained they key, it would be OK. So you could do:
<hr onclick="var foo = 'D3FC219A'; ..." />
Or, you could require the handler to set a navigator.scriptkey property to the correct key before you could do anything apart from assign variables. But that’s rather hacky too, and perhaps harder to implement, as you need to sandbox already-running script. (Either of these ideas would obsolete the content-type-parameter method.) Better suggestions welcomed. (We could define a new attribute, perhaps through the WHAT-WG. That might be cleaner, but it wouldn’t solve the event handler problem unless the attribute was made applicable to all tags.)
So how does this approach compare with Content-Restrictions? It’s a single layer idea – i.e. if it’s breached, and the attacker manages to e.g. inject script inside a block which is labelled as safe, then it’s game over. But it does reduce the attack surface. Content-Restrictions, on the other hand, is layered – if one restriction doesn’t prevent an attack, another one might. As a simple example, for “script=head,cookies=none”, even if you managed to inject script into the head, you couldn’t read cookies.