Proteside Docs

Content Security Policy and headers

The CSP directives the SDK needs, violation reports, monitored headers and how they relate to PCI DSS.

If your checkout uses a Content Security Policy (CSP), it must allow the Proteside snippet. The dashboard doesn't generate a CSP for you: this page lists what the SDK actually uses in the browser, so you can add it to your store's policy.

Required directives

DirectiveValuePurpose
script-srchash, nonce or 'unsafe-inline' for the snippet's inline <script> tagsRun the bootstrapper, which includes the window.__PROTE_INLINE__ configuration when the store has inline rules.
script-srchttps://cdn.proteside.comLoad shield.js.
connect-srchttps://app.proteside.comFetch the configuration (/api/sdk/config) and send events (/api/sdk/events, via fetch and sendBeacon).
connect-src'self'Read the page's own security headers (see below).
connect-srcorigins of the page's external scripts (optional)Compute the content hash of third-party scripts.

Without connect-src for app.proteside.com, the SDK loads and runs, but no events reach the dashboard. Without the optional permission for script origins, the SDK doesn't compute the hash of those scripts: they stay in the inventory as monitored, with no hash, and the browser generates violation reports for those hosts.

The snippet's inline scripts

The bootstrapper is inline and must stay inline (see Installing the snippet). Choose a way to authorize it:

  • Hash ('sha256-…'): authorizes exactly that content. The hash changes when the script's content changes: every time you paste a snippet from a new version and, if the store has inline rules, whenever you paste the snippet again after changing rules or Google Tag Manager containers, because the window.__PROTE_INLINE__ configuration sits at the start of the same script. Older snippets, with that configuration in a separate tag, need a second hash for it.
  • Nonce: if your server already generates a nonce per response, add the nonce attribute to the snippet's <script> tags when you paste it into your template. The dashboard's snippet doesn't include a nonce.
  • 'unsafe-inline': works, but allows any inline script and weakens the policy. Not recommended on payment pages.

The safest way to get the hash is to let the browser compute it: publish the CSP without the hash (preferably in Content-Security-Policy-Report-Only mode), open the checkout and look at the violation message in the console. It gives you the 'sha256-…' value of the blocked script. To compute it locally, use exactly the content between <script> and </script>, with no trailing newline:

Compute the bootstrapper hash
# bootstrapper.js = content between <script> and </script>, copied from the snippet
printf '%s' "$(cat bootstrapper.js)" | openssl dgst -sha256 -binary | openssl base64

Example header

An example for a checkout on mystore.com with Stripe. Adapt the other origins to your store.

Checkout page response header
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'sha256-BOOTSTRAPPER_HASH' https://cdn.proteside.com https://js.stripe.com;
  connect-src 'self' https://app.proteside.com https://api.stripe.com;
  frame-src https://js.stripe.com;
  img-src 'self' data:;
  style-src 'self';
  report-uri https://app.proteside.com/api/sdk/csp-report?key=pk_live_3f9c1a7b2e4d6f8a0c1e3b5d7f9a1c3e;
  report-to proteside
Reporting-Endpoints: proteside="https://app.proteside.com/api/sdk/csp-report?key=pk_live_3f9c1a7b2e4d6f8a0c1e3b5d7f9a1c3e"

The real header goes on a single line; the line breaks above are only for readability. If your snippet uses the older format, with window.__PROTE_INLINE__ in a separate <script> tag, add that tag's hash too.

If you use the static badge, it uses style="…" attributes and needs style-src 'unsafe-inline' or style-src-attr 'unsafe-inline'. The SDK itself doesn't need style-src or img-src.

Violation reports

Proteside receives CSP reports at the address below. It doesn't appear on any dashboard screen; use your SDK key in the key parameter:

https://app.proteside.com/api/sdk/csp-report?key=pk_live_3f9c1a7b2e4d6f8a0c1e3b5d7f9a1c3e
  • It accepts both formats: report-uri and report-to (Reporting API).
  • The total shows up in SDK Health, in the CSP reports (48 h) card.
  • A script-src or connect-src violation for a host that's not in the store's script inventory becomes a CSP_VIOLATION alert, with low severity. Violations of other directives are only counted.
  • Above 600 reports per minute per key, the excess is discarded.

To test a new policy without breaking the checkout, publish it first as Content-Security-Policy-Report-Only, watch the reports, and then switch to Content-Security-Policy.

Monitored security headers

To support detecting header changes, the SDK reads the payment page's security headers on every page load and every Proteside.pageChanged():

Content-Security-Policy, Content-Security-Policy-Report-Only, Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy, Cross-Origin-Resource-Policy, Access-Control-Allow-Origin and Set-Cookie (the latter only as "not readable in the browser").

The value of each header that's present is sent to the dashboard. When a value changes, the dashboard creates the HEADER_CHANGED alert. Headers appear in PCI DSS Evidence, on the Headers tab.

One extra GET request per pageview

To read the headers, the SDK makes an additional GET request to the page's own URL, with the customer's cookies and no cache. If your checkout performs an action when it receives a GET (creating an order, reserving stock, generating a charge), that action will happen twice. Make sure the payment page's GET has no side effects.

Subresource Integrity (SRI)

Don't use the integrity attribute on the shield.js tag. SRI isn't currently viable, for two reasons:

  1. The URL is mutable. The same address receives every new SDK version, so the hash would change with each release and the browser would start refusing the script.
  2. The CDN doesn't send CORS headers. A <script integrity crossorigin="anonymous"> requires CORS, and the browser would block the load.

As a preventive control, restrict script-src to https://cdn.proteside.com and authorize the inline bootstrapper by hash or nonce. The Proteside inventory records which scripts on your page use integrity and nonce.

How this relates to PCI DSS 4.0

RequirementWhat it asks forHow Proteside and CSP help
6.4.3Manage payment page scripts executed in the browser: an inventory with justification, authorization of each script, and integrity assurance.The SDK builds the inventory with content hashes; authorization with justification happens in Scripts; rules block unauthorized scripts. CSP limits where scripts can be loaded from.
11.6.1Detect and alert on unauthorized changes to the HTTP headers and content of the payment page, as received by the browser.The SDK reads the security headers on every pageview and detects new or modified scripts; the dashboard raises HEADER_CHANGED, SCRIPT_INTEGRITY_MISMATCH and the other alerts.

Proteside generates evidence for these requirements in PCI DSS Evidence. The compliance assessment remains the responsibility of your assessor (QSA) or your self-assessment questionnaire. See PCI DSS Evidence.

Next steps

On this page