Fortunately, two browser-side mechanisms have been introduced to mitigate or limit the impact from externally-included resources: Subresource Integrity and sandboxing.
Subresource Integrity (SRI) allows developers to pin down certain versions of scripts or stylesheets which are included from external domains. The goal is to ensure that the external script has not been modified inadvertently, or intentionally replaced or altered by an attacker. A cryptographic hash is used to ensure that the version included in the website has not been tampered with:
<script src="https://external.cdn.ch/example-framework.js" integrity="sha512-z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYX ysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==" crossorigin="anonymous"></script>
As soon as the content of the external resource “example-framework.js” changes, the hash set on the consuming website does no longer match the script’s hash and the script will not be run by the browser. Note that Cross-Origin Resource Sharing (CORS) must be enabled on the Content Delivery Network’s side to be able to use the integrity attribute, or else the script will not load at all, even with a correct hash.
The SHA-512 hash to pin down external resources can be calculated as follows:
cat example-framework.js | openssl dgst -sha512 -binary | openssl base64 -A
While only the script and link tags support the integrity attribute by the time of writing, other tags will probably follow, enabling developers to also ensure the integrity of images or other content embedded from externally.
The crossorigin attribute defines whether or not the browser should send credentials when fetching the external resource. It defaults to anonymous if an invalid value is given. The values are defined as follows:
|anonymous (or empty string)||Anonymous||Requests for the element will have their mode set to “cors” and their credentials mode set to “same-origin”. (i.e. CORS request and credentials for the external domain are not sent with the request)|
|use-credentials||Use Credentials||Requests for the element will have their mode set to “cors” and their credentials mode set to “include”. (i.e. CORS request and credentials for the external domain are sent with the request)|
|[crossorigin attribute not present]||No CORS||Requests for the element will have their mode set to “no-cors”. As a consequence, data cannot be read cross-origin.|
SRI only makes sense if the website is secured with TLS. If an attacker is able to intercept and alter the website he can inject his own scripts and strip the hashes or generate them on-the-fly.
Since hashes like MD5 or SHA-1 are prone to collision attacks, they should be avoided for pinning external resources. SHA-384 or SHA-512 are considered secure.
Note that only Firefox, Chrome and Opera support SRI at the time of writing. This means that users of Internet Explorer or Edge do not benefit from the SRI protection. Therefore it is still preferable to host the resources on your own domain, than to depend on SRI.
While SRI can be used to ensure the integrity of external resources, it does not feature a report mechanism that tells the including party if a script has been modified and therefore does no longer run in the user’s browsers. A report-uri mechanism, as known from HSTS, HPKP or CSP, would need to be custom-developed.
From a security standpoint, it is a bad idea to include external resources directly into the website, because this is giving them full access to the website’s Document Object Model (DOM). A resource could thus access and alter the whole content of the website. When confined in an iframe, access to the parent’s DOM is restricted. It is however still possible to open pop-up windows from within the iframe, display dialogs or perform other unwanted actions. With the HTML5 feature sandboxing, it is possible to further restrict the behavior of “iframed” content.
<iframe src="//external.cdn.ch/example_resource.html" id="sandboxed_frame" sandbox="" height="500" width="700"></iframe> <iframe src="//external.cdn.ch/example_resource.html" id="sandboxed_frame" sandbox height="500" width="700"></iframe>
|allow-popups||Enables iframe content to open pop-up windows.|
|allow-pointer-lock||Enables iframe content to use the Pointer Lock API. The mouse movements can be tracked and the mouse pointer can be hidden.|
|allow-popups-to-escape-sandbox||Enables iframe content to create pop-up windows without sandbox restrictions. (Why would you want to do that?!?)|
|allow-modals||Enables iframe content to display modal windows such as alert();, prompt(); or through showModal().|
|allow-top-navigation||Enables iframe content to load content to the top-level browsing context, e.g. via href or target=”_top”.|
Sandboxed iframe content resides in a custom origin, isolating it from the originating domain. It can therefore not perform requests or read data from its original origin. This directive allows the iframe content to run in the originating domain, thus removing those restrictions.
|allow-forms||Enables iframe content to submit forms.|
|allow-presentation||Enables iframe content to start presentations.|
Our next Web Application Security courses
- 14./15.03.2017, Web Application Security Basic, Bern
- 16./17.03.2017, Web Application Security Advanced, Bern
- 04./05.04.2107, Web Application Security Basic, Berlin
- 06./07.04.2017, Web Application Security Advanced, Berlin
- 26./27.09.2017, Web Application Security Basic, Zurich
- 28./29.09.2017, Web Application Security Advanced, Zurich