On our site, external scripts from ad provider (all Javascript) occasionally navigate the user to some malware site.
Any JS-code can be loaded from the ad provider (e.g. sometimes it creates an iframe to display the ad, sometime the ad is displayed directly in the main page).
I wonder how to safely prevent any external script from triggering top level navigation, whether the script is executed from within an iframe or not.
Current solution is to add CSP sandbox header in every response:
header( 'Content-Security-Policy: sandbox allow-downloads allow-forms allow-modals allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-storage-access-by-user-activation allow-top-navigation-by-user-activation allow-top-navigation-to-custom-protocols;' );
The strategy is to prevent top level navigation by omitting the sandbox allow-top-navigation
header.
Is this a sufficient solution in order to prevent top level navigation? Is there a better way to achieve this?
2
Answers
It is not sufficient because in your case you also need to grant
allow-scripts
, which permits navigation.For instance, the following third party javascript would navigate to an arbitary page.
How to protect against it?
You’ll need a known-good version of the 3rd party assets, and load them with a
nonce
. That will ensure that other versions won’t run in your page.I agree with @Eric Fortis’s answer here but I would also like to say that if your ads are redirecting to malware sites, then the solution is to get a different ad provider that doesn’t sponsor malware, such as Google AdSense.
Not only are you supporting malware developers with the ad provider you’re using, you’re also going to lose repeat business because of the affected visitors. Additionally, most shady auto-links like that also cheat the legitimate sites that are paying for click-thru by forcing a click.
You can force shut-off redirects in the browser settings. In Chrome, simply enable safe browsing. Shady activities such as these will eventually be auto-blocked by the browsers, but for now it’s a setting.