- Replace the deprecated X-Frame-Options HTTP header with its successor, Content Security Policies
- Set Content Security Policies (CSP)
Many sites protect visitors from cross-site scripting (XSS), clickjacking, and other code injection attacks by adding an X-Frame-Options header. However, this can block Optimizely from running parts of the snippet on your pages or sending tracking information back to our servers.
For this reason, you may need to update your site to include Content Security Policy (CSP) header in order to run Optimizely and keep your customers safe from outside attacks.
Implement Content Security Policies (CSP)
X-Frame-Options is a deprecated web standard that has been succeeded by Content Security Policies, which allows for greater customization, including the ability to allowlist Optimizely.
For Optimizely, add the following directives to the CSP header for your pages:
frame-src https://a[your-account-id-here].cdn.optimizely.com https://a[your-account-id-here].cdn-pci.optimizely.com; script-src 'self' https://*.optimizely.com https://optimizely.s3.amazonaws.com https://cdn-assets-prod.s3.amazonaws.com 'nonce-[your-nonce-value]' 'strict-dynamic'; connect-src https://logx.optimizely.com https://*.optimizely.com; img-src https://cdn.optimizely.com; style-src 'unsafe-inline';
How the CSP directives work
Each of the five directives in the CSP policy has a specific purpose:
frame-src https://a[your-account-id-here].cdn.optimizely.com https://a[your-account-id-here].cdn-pci.optimizely.com
This enables cross-domain behavioral targeting. If you don’t need cross-domain behavioral targeting, you can omit this directive. Note that the second URL is only necessary if PCI is enabled.
script-src 'self' https://*.optimizely.com https://optimizely.s3.amazonaws.com https://cdn-assets-prod.s3.amazonaws.com 'nonce-[your-nonce-value]' 'strict-dynamic';
This enables the Optimizely client script, the preview mode client, and Optimizely geotargeting. In browsers which support 'strict-dynamic' (Content Security Policy Level 3), it's only necessary to apply the "nonce" value to the Optimizely snippet script tag. If you only need to support such browsers, the directive can be simplified to:
script-src 'nonce-[your-nonce-value]' 'strict-dynamic'
strict-dynamic for more information about backwards compatibility in
connect-src https://logx.optimizely.com https://*.optimizely.com
This line enables the Optimizely client to log events.
This allows the Optimizely client to load images that have been uploaded using the Visual Editor.
This is required for experiment CSS changes to be applied. It is also required to avoid a jQuery feature detection error for any jQuery versions below 1.8.3.
Now your browser will allow your site and Optimizely to load your pages in an iframe, while blocking attempts from all other parties.
Features that require explicit allowlisting
Some features will not be available in Optimizely unless
unsafe-eval' is included in your policy's
To enable these features, simply add this directive to your CSP header:
Experiment custom code and conditional activation code are not checked for syntax in the UI. Use this tool to check the syntax of your custom code.
Example of a complete CSP policy
Once you've gone through the steps above, the set of directives in your Content Security Policies may look something like this:
Content-Security-Policy= default-src 'none'; frame-src https://a[your-account-id-here].cdn.optimizely.com https://a[your-account-id-here].cdn-pci.optimizely.com; script-src 'self' https://*.optimizely.com https://optimizely.s3.amazonaws.com https://cdn-assets-prod.s3.amazonaws.com; connect-src https://*.optimizely.com; img-src https://app.optimizely.com https://cdn.optimizely.com; style-src 'unsafe-inline'
Since you're likely to use other third-party tools in addition to Optimizely, your rules might look different. Make sure to test them thoroughly before going live with these restrictions.
Some browsers have support for a directive
require-trusted-types-for 'script' that limits the ability of scripts to generate and update the HTML on a site. Optimizely cannot apply changes for experiments without this ability, so please make sure this directive is not included in your policy.
You can soft-launch your changes in report-only mode so that the restrictions don't affect your visitors, but violations are collected (e.g. via report-uri.io) so you can adapt and fine-tune your CSP.
Occasionally, we'll get a customer asking: "how do I add Optimizely's app server IPs to an allowlist for my Content Security Policy" or "What IPs will a Full Stack/Mobile webhook POST originate from so I can avoid having an insecure webhook handler"
These people are operating on the assumption that we manage our own app servers, and have a range of external IPs that an Optimizely server might belong to. That assumption is wrong. Here's why: https://cloud.google.com/appengine/kb/#static-ip
This also affects Full Stack/Mobile Webhook POSTs. Since a webhook POST would still originate from our app servers (familiarize yourself with webhooks here: https://developers.optimizely.com/x/...=node#webhooks).
For the Content-Security Policy, you probably all know the answer. They need to allowlist the domain instead of IP addresses. They can allow all traffic from `*.optimizely.com`
For webhooks, they'll need to read the `X-Hub-Signature` header of our POSTs, which contains a secret key they can use to validate the request. You can read about that here: https://developers.optimizely.com/x/...uring-webhooks