-
Notifications
You must be signed in to change notification settings - Fork 84
Description
Context
whatwg/html#2300 (particularly the comment thread)
https://codereview.chromium.org/2657623005
Summary
Let's add a new script-src keyword ('safe-dynamic-markup'
) which will prevent the execution of scripts added to the DOM via a parser-pased JS API (Element.innerHTML
, document.write
, etc). When a new script element is added, the user-agent should check if its parser-inserted flag is set, and if the element has been added via a JS API, and if both conditions are met and the 'safe-dynamic-markup'
keyword is specified, block the execution of the script and report a violation.
To be effective, this also has to apply to scripts inside frames which inherit the policy of the embedding page (iframe#srcdoc
).
Background
There are three main kinds of DOM APIs which lead to DOM XSS bugs:
eval()
& co. which directly execute scripts based on their argumentswindow.open()
, assignments tolocation.href
, etc which allow script execution via javascript: URIs.- Parser-based APIs such as
innerHTML
,document.write
and related functions.
CSP already mitigates the first two types (via a policy without 'unsafe-eval'
and 'unsafe-inline'
respectively), and it prevents the execution of inline event handlers ('onclick'
, etc) if an injection into a parser-based API happens. However, an injection into such an API can still lead to script execution: in whitelist-based CSP, if the policy contains a domain with a "bypassable endpoint" (e.g. a JSONP endpoint or a hosted copy of AngularJS) an attacker will be able to source it as a script (<iframe srcdoc='<script src=//cdn.org/angular.js></script>'></iframe>
and bypass the policy; in a nonce-based policy, an attacker who exfiltrates the nonce via dangling markup or another technique will be able to use the stolen nonce (<iframe srcdoc='<script nonce=[stolen]>alert()</script>'></iframe>
).
If we allow developers to block the execution of all scripts added via parser-based JS APIs, it will get us fairly close to preventing the exploitation of DOM XSS via native platform APIs (though some JS libraries might still open up their own new attack vectors).
Compatibility
In a lucky turn of events, many applications with a useful CSP (without 'unsafe-inline'
) are already compatible with the proposed keyword because adding new script elements at runtime usually happens via programmatic APIs (createElement('script')
). The patterns which would need to be refactored are:
document.write("<script>...")
-- would need to be refactored to use programmatic APIs.element.innerHTML = "<iframe srcdoc='<script …>'></iframe>"
-- as above, but this a rare pattern. Note that a direct assignment of<script>...</script>
to innerHTML is not a problem because this doesn't execute scripts as discussed in<iframe srcdoc="<script>">
should not execute when inserted viainnerHTML
. whatwg/html#2300.
Overall it seems like it could be a useful defense-in-depth against DOM XSS bugs and bypasses of CSP, with a reasonably high chance of being adoptable in many applications without significant effort.