<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Lukas Weichselbaum on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Lukas Weichselbaum</name>
  </author>
  <link href="https://web.dev/authors/lwe/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/admin/SR3DdHwfeqxp5k9ojcr6.jpg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Our latest news, updates, and stories by Lukas Weichselbaum.</subtitle>
  
  
  <entry>
    <title>Mitigate cross-site scripting (XSS) with a strict Content Security Policy (CSP)</title>
    <link href="https://web.dev/strict-csp/"/>
    <updated>2021-03-15T00:00:00Z</updated>
    <id>https://web.dev/strict-csp/</id>
    <content type="html" mode="escaped">&lt;h2 id=&quot;why-should-you-deploy-a-strict-content-security-policy-csp&quot;&gt;Why should you deploy a strict Content Security Policy (CSP)? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#why-should-you-deploy-a-strict-content-security-policy-csp&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.google.com/about/appsecurity/learning/xss/&quot; rel=&quot;noopener&quot;&gt;Cross-site scripting
(XSS)&lt;/a&gt;—the ability to
inject malicious scripts into a web application—has been one of the biggest web
security vulnerabilities for over a decade.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/CSP&quot; rel=&quot;noopener&quot;&gt;Content Security Policy
(CSP)&lt;/a&gt; is an added layer
of security that helps to mitigate XSS. Configuring a CSP involves adding the
Content-Security-Policy HTTP header to a web page and setting values to control
what resources the user agent is allowed to load for that page. This article
explains how to use a CSP based on nonces or hashes to mitigate XSS instead of
the commonly used host-allowlist-based CSPs which often leave the page exposed
to XSS as they can be &lt;a href=&quot;https://research.google.com/pubs/pub45542.html&quot; rel=&quot;noopener&quot;&gt;bypassed in most
configurations&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow color-secondary-box-text bg-secondary-box-bg&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Highlighter pen&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M10.22 9.49l-5.91 6c-.77.8-.7 2.05.08 2.85L.77 22h5.68l.74-.75c.78.81 1.95.86 2.73.05l5.96-6.05-5.66-5.76zm12.46-4l-2.82-2.87c-.78-.8-2.07-.84-2.84-.04l-5.75 5.85 5.66 5.75 5.69-5.78c.77-.81.83-2.11.06-2.91z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Key Term&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; A &lt;em&gt;nonce&lt;/em&gt; is a random number used only once that can be used to mark a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag as trusted. &lt;/div&gt;&lt;/aside&gt;
&lt;aside class=&quot;aside flow color-secondary-box-text bg-secondary-box-bg&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Highlighter pen&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M10.22 9.49l-5.91 6c-.77.8-.7 2.05.08 2.85L.77 22h5.68l.74-.75c.78.81 1.95.86 2.73.05l5.96-6.05-5.66-5.76zm12.46-4l-2.82-2.87c-.78-.8-2.07-.84-2.84-.04l-5.75 5.85 5.66 5.75 5.69-5.78c.77-.81.83-2.11.06-2.91z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Key Term&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; A hash function is a mathematical function that converts an input value into a compressed numerical value—a hash. A &lt;em&gt;hash&lt;/em&gt; (such as &lt;a href=&quot;https://en.wikipedia.org/wiki/SHA-2&quot;&gt;SHA-256&lt;/a&gt;) can be used to mark an inline &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag as trusted. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;A Content Security Policy based on nonces or hashes is often called a &lt;em&gt;strict
CSP&lt;/em&gt;. When an application uses a strict CSP, attackers who find HTML injection
flaws will generally not be able to use them to force the browser to execute
malicious scripts in the context of the vulnerable document. This is because
strict CSP only permits hashed scripts or scripts with the correct nonce value
generated on the server, so attackers cannot execute the script without knowing
the correct nonce for a given response.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; To protect your site from XSS, make sure to sanitize user input &lt;em&gt;and&lt;/em&gt; use CSP as an extra security layer. CSP is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Defense_in_depth_(computing)&quot;&gt;defense-in-depth&lt;/a&gt; technique that can prevent the execution of malicious scripts, but it&#39;s not a substitute for avoiding (and promptly fixing) XSS bugs. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;compatibility&quot;&gt;Browser compatibility &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#compatibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Strict CSP is supported in all modern browser engines.&lt;/p&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 52, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      52
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 52, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      52
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 15.4, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      15.4
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#strict-dynamic#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;h3 id=&quot;why-a-strict-csp-is-recommended-over-allowlist-csps&quot;&gt;Why a strict CSP is recommended over allowlist CSPs &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#why-a-strict-csp-is-recommended-over-allowlist-csps&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If your site already has a CSP that looks like this: &lt;code&gt;script-src www.googleapis.com&lt;/code&gt;, it may not be effective against cross-site scripting! This
type of CSP is called an allowlist CSP and it has a couple of downsides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It requires a lot of customization.&lt;/li&gt;
&lt;li&gt;It can be &lt;a href=&quot;https://research.google.com/pubs/pub45542.html&quot; rel=&quot;noopener&quot;&gt;bypassed in most
configurations&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes allowlist CSPs generally ineffective at preventing attackers from
exploiting XSS. That&#39;s why it&#39;s recommended to use a strict CSP based on
cryptographic nonces or hashes, which avoids the pitfalls outlined above.&lt;/p&gt;
&lt;div class=&quot;switcher&quot;&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;worse&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Allowlist CSP&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Doesn&#39;t effectively protect your site. ❌&lt;/li&gt;
&lt;li&gt;Must be highly customized. 😓&lt;/li&gt;
&lt;/ul&gt;
&lt;/figure&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;better&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Strict CSP&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Effectively protects your site. ✅&lt;/li&gt;
&lt;li&gt;Always has the same structure. 😌&lt;/li&gt;
&lt;/ul&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 id=&quot;what-is-a-strict-content-security-policy&quot;&gt;What is a strict Content Security Policy? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#what-is-a-strict-content-security-policy&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A strict Content Security Policy has the following structure and is enabled by
setting one of the following HTTP response headers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nonce-based strict CSP&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Content-Security-Policy:&lt;br /&gt;  script-src &#39;nonce-{RANDOM}&#39; &#39;strict-dynamic&#39;;&lt;br /&gt;  object-src &#39;none&#39;;&lt;br /&gt;  base-uri &#39;none&#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;img alt=&quot;&quot; decoding=&quot;async&quot; height=&quot;279&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/er4BaGCJzBwDaESFKfZd.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hash-based strict CSP&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Content-Security-Policy:&lt;br /&gt;  script-src &#39;sha256-{HASHED_INLINE_SCRIPT}&#39; &#39;strict-dynamic&#39;;&lt;br /&gt;  object-src &#39;none&#39;;&lt;br /&gt;  base-uri &#39;none&#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; This is the most stripped-down version of a strict CSP. You&#39;ll need to tweak it to make it effective across browsers. See &lt;a href=&quot;https://web.dev/strict-csp/#step-4:-add-fallbacks-to-support-safari-and-older-browsers&quot;&gt;add a fallback to support Safari and older browsers&lt;/a&gt; for details. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The following properties make a CSP like the one above &amp;quot;strict&amp;quot; and hence
secure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Uses nonces &lt;code&gt;&#39;nonce-{RANDOM}&#39;&lt;/code&gt; or hashes &lt;code&gt;&#39;sha256-{HASHED_INLINE_SCRIPT}&#39;&lt;/code&gt; to
indicate which &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags are trusted by the site&#39;s developer and should
be allowed to execute in the user&#39;s browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sets &lt;a href=&quot;https://www.w3.org/TR/CSP3/#strict-dynamic-usage&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&#39;strict-dynamic&#39;&lt;/code&gt;&lt;/a&gt; to
reduce the effort of deploying a nonce- or hash-based CSP by automatically
allowing the execution of scripts that are created by an already trusted
script. This also unblocks the use of most third party JavaScript libraries
and widgets.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Not based on URL allowlists and therefore doesn&#39;t suffer from &lt;a href=&quot;https://speakerdeck.com/lweichselbaum/csp-is-dead-long-live-strict-csp-deepsec-2016?slide=15&quot; rel=&quot;noopener&quot;&gt;common CSP
bypasses&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Blocks untrusted inline scripts like inline event handlers or &lt;code&gt;javascript:&lt;/code&gt;
URIs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Restricts &lt;code&gt;object-src&lt;/code&gt; to disable dangerous plugins such as Flash.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Restricts &lt;code&gt;base-uri&lt;/code&gt; to block the injection of &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt; tags. This prevents
attackers from changing the locations of scripts loaded from relative URLs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Another advantage of a strict CSP is that the CSP always has the same structure and doesn&#39;t need to be customized for your application. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;adopting-a-strict-csp&quot;&gt;Adopting a strict CSP &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#adopting-a-strict-csp&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To adopt a strict CSP, you need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Decide if your application should set a nonce- or hash-based CSP.&lt;/li&gt;
&lt;li&gt;Copy the CSP from the &lt;a href=&quot;https://web.dev/strict-csp/#what-is-a-strict-content-security-policy&quot;&gt;What is a strict Content Security
Policy&lt;/a&gt; section and set it as a
response header across your application.&lt;/li&gt;
&lt;li&gt;Refactor HTML templates and client-side code to remove patterns that are
incompatible with CSP.&lt;/li&gt;
&lt;li&gt;Deploy your CSP.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can use &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt;
(v7.3.0 and above with flag &lt;code&gt;--preset=experimental&lt;/code&gt;) &lt;strong&gt;Best Practices&lt;/strong&gt; audit throughout this process to check
whether your site has a CSP, and whether it&#39;s strict enough to be effective
against XSS.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse report warning that no CSP is found in enforcement mode.&quot; decoding=&quot;async&quot; height=&quot;78&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 730px) 730px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9B7J9oWjgsWbuE84mmxDaY37Wpw2/42a4iEEKsD4T3yU47vNQ.png?auto=format&amp;w=1460 1460w&quot; width=&quot;730&quot; /&gt;
&lt;h3 id=&quot;step-1-decide-if-you-need-a-nonce-or-hash-based-csp&quot;&gt;Step 1: Decide if you need a nonce- or hash-based CSP &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#step-1-decide-if-you-need-a-nonce-or-hash-based-csp&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are two types of strict CSPs, nonce- and hash-based. Here&#39;s how they work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nonce-based CSP&lt;/strong&gt;: You generate a random number &lt;em&gt;at runtime&lt;/em&gt;, include it in
your CSP, and associate it with every script tag in your page. An attacker
can&#39;t include and run a malicious script in your page, because they would need
to guess the correct random number for that script. This only works if the
number is not guessable and newly generated at runtime for every response.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hash-based CSP&lt;/strong&gt;: The hash of every inline script tag is added to the CSP.
Note that each script has a different hash. An attacker can&#39;t include and run
a malicious script in your page, because the hash of that script would need to
be present in your CSP.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Criteria for choosing a strict CSP approach:&lt;/p&gt;
&lt;div&gt;
  &lt;table&gt;
      &lt;caption&gt;Criteria for choosing a strict CSP approach&lt;/caption&gt;
      &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;Nonce-based CSP&lt;/th&gt;
        &lt;td&gt;For HTML pages rendered on the server where you can create a new random token
(nonce) for every response.&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;th&gt;Hash-based CSP&lt;/th&gt;
        &lt;td&gt;For HTML pages served statically or those that need to be cached. For example,
single-page web applications built with frameworks such as Angular, React or others, that are
statically served without server-side rendering.&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;h3 id=&quot;step-2-set-a-strict-csp-and-prepare-your-scripts&quot;&gt;Step 2: Set a strict CSP and prepare your scripts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#step-2-set-a-strict-csp-and-prepare-your-scripts&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When setting a CSP, you have a few options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Report-only mode (&lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt;) or enforcement mode
(&lt;code&gt;Content-Security-Policy&lt;/code&gt;). In report-only, the CSP won&#39;t block resources
yet—nothing will break—but you&#39;ll be able to see errors and receive reports
for what would have been blocked. Locally, when you&#39;re in the process of
setting a CSP, this doesn&#39;t really matter, because both modes will show you
the errors in the browser console. If anything, enforcement mode will make it
even easier for you to see blocked resources and tweak your CSP, since your
page will look broken. Report-only mode becomes most useful later in the
process (see &lt;a href=&quot;https://web.dev/strict-csp/#step-5:-deploy-your-csp&quot;&gt;Step 5&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Header or HTML &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tag. For local development, a &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tag may be more
convenient for tweaking your CSP and quickly seeing how it affects your site.
However:
&lt;ul&gt;
&lt;li&gt;Later on, when deploying your CSP in production, it is recommended to set it
as an HTTP header.&lt;/li&gt;
&lt;li&gt;If you want to set your CSP in report-only mode, you&#39;ll need to set it as a
header—CSP meta tags don&#39;t support report-only mode.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span id=&quot;nonce-based-csp&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;
  Option A: Nonce-based CSP
&lt;/summary&gt;
&lt;p&gt;Set the following &lt;code&gt;Content-Security-Policy&lt;/code&gt; HTTP response header in your
application:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Content-Security-Policy:&lt;br /&gt;  script-src &#39;nonce-{RANDOM}&#39; &#39;strict-dynamic&#39;;&lt;br /&gt;  object-src &#39;none&#39;;&lt;br /&gt;  base-uri &#39;none&#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Replace the &lt;code&gt;{RANDOM}&lt;/code&gt; placeholder with a &lt;em&gt;random&lt;/em&gt; nonce that is regenerated &lt;strong&gt;on every server response&lt;/strong&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h4 id=&quot;generate-a-nonce-for-csp&quot;&gt;Generate a nonce for CSP &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#generate-a-nonce-for-csp&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A nonce is a random number used only once per page load. A nonce-based CSP can
only mitigate XSS if the nonce value is &lt;strong&gt;not guessable&lt;/strong&gt; by an attacker. A
nonce for CSP needs to be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A cryptographically &lt;strong&gt;strong random&lt;/strong&gt; value (ideally 128+ bits in length)&lt;/li&gt;
&lt;li&gt;Newly &lt;strong&gt;generated for every response&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Base64 encoded&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are some examples on how to add a CSP nonce in server-side frameworks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://django-csp.readthedocs.io/en/latest/nonce.html&quot; rel=&quot;noopener&quot;&gt;Django (python)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Express (JavaScript):&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;express&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Generate a new random nonce value for every response.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; nonce &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; crypto&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;randomBytes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;base64&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Set the strict nonce-based CSP response header&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; csp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;script-src &#39;nonce-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;nonce&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39; &#39;strict-dynamic&#39;; object-src &#39;none&#39;; base-uri &#39;none&#39;;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Content-Security-Policy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; csp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Every &amp;lt;script&gt; tag in your application should set the `nonce` attribute to this value.&lt;/span&gt;&lt;br /&gt;    response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;template&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;nonce&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; nonce &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;add-a-nonce-attribute-to-lessscriptgreater-elements&quot;&gt;Add a &lt;code&gt;nonce&lt;/code&gt; attribute to &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; elements &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#add-a-nonce-attribute-to-lessscriptgreater-elements&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;With a nonce-based CSP, every &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element must have a &lt;code&gt;nonce&lt;/code&gt; attribute
which matches the random nonce value specified in the CSP header (all scripts
can have the same nonce). The first step is to add these attributes to all
scripts:&lt;/p&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;worse&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Blocked by CSP&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/path/to/script.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figcaption class=&quot;compare__caption&quot;&gt;
&lt;p&gt;CSP will block these scripts, because they don&#39;t have
&lt;code&gt;nonce&lt;/code&gt; attributes.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;better&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Allowed by CSP&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nonce&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;${NONCE}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/path/to/script.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nonce&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;${NONCE}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figcaption class=&quot;compare__caption&quot;&gt;
&lt;p&gt;CSP will allow the execution of these scripts if &lt;code&gt;${NONCE}&lt;/code&gt;
is replaced with a value matching the nonce in the CSP response header. Note
that some browsers will hide the &lt;code&gt;nonce&lt;/code&gt; attribute when inspecting the page
source.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Gotchas&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; With &lt;code&gt;&#39;strict-dynamic&#39;&lt;/code&gt; in your CSP, you&#39;ll only have to add nonces to &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags that are present in the initial HTML response.&lt;code&gt;&#39;strict-dynamic&#39;&lt;/code&gt; allows the execution of scripts dynamically added to the page, as long as they were loaded by a safe, already-trusted script (see the &lt;a href=&quot;https://www.w3.org/TR/CSP3/#strict-dynamic-usage&quot;&gt;specification&lt;/a&gt;). &lt;/div&gt;&lt;/aside&gt;
&lt;/details&gt;
&lt;p&gt;&lt;span id=&quot;hash-based-csp&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;
  Option B: Hash-based CSP Response Header
&lt;/summary&gt;
&lt;p&gt;Set the following &lt;code&gt;Content-Security-Policy&lt;/code&gt; HTTP response header in your
application:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Content-Security-Policy:&lt;br /&gt;  script-src &#39;sha256-{HASHED_INLINE_SCRIPT}&#39; &#39;strict-dynamic&#39;;&lt;br /&gt;  object-src &#39;none&#39;;&lt;br /&gt;  base-uri &#39;none&#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;For several inline scripts, the syntax is as follows:
&lt;code&gt;&#39;sha256-{HASHED_INLINE_SCRIPT_1}&#39;  &#39;sha256-{HASHED_INLINE_SCRIPT_2}&#39;&lt;/code&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; The &lt;code&gt;{HASHED_INLINE_SCRIPT}&lt;/code&gt; placeholder must be replaced with a base64-encoded SHA-256 hash of an inline script that can be used to load other scripts (see next section). You can calculate SHA hashes of static inline &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; blocks with this &lt;a href=&quot;https://strict-csp-codelab.glitch.me/csp_sha256_util.html&quot;&gt;tool&lt;/a&gt;. An alternative is to inspect the CSP violation warnings in Chrome&#39;s developer console, which contains hashes of blocked scripts, and add these hashes to the policy as &#39;sha256-…&#39;.  A script injected by an attacker will be blocked by the browser as only the hashed inline script and any scripts dynamically added by it will be allowed to execute by the browser. &lt;/div&gt;&lt;/aside&gt;
&lt;h4 id=&quot;load-sourced-scripts-dynamically&quot;&gt;Load sourced scripts dynamically &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#load-sourced-scripts-dynamically&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;All scripts that are externally sourced need to be loaded dynamically via an
inline script, because CSP hashes are supported across browsers only for inline
scripts (hashes for sourced scripts are &lt;a href=&quot;https://wpt.fyi/results/content-security-policy/script-src/script-src-sri_hash.sub.html?label=master&amp;amp;label=experimental&amp;amp;aligned&quot; rel=&quot;noopener&quot;&gt;not well-supported across
browsers&lt;/a&gt;).&lt;/p&gt;
&lt;img alt=&quot;&quot; decoding=&quot;async&quot; height=&quot;333&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/B2YsfJDYw8PRI6kJI7Bs.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;worse&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Blocked by CSP&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.org/foo.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.org/bar.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figcaption class=&quot;compare__caption&quot;&gt;
&lt;p&gt;CSP will block these scripts since only inline-scripts can
be hashed.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;better&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Allowed by CSP&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; scripts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://example.org/foo.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://example.org/bar.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;scripts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;scriptUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;script&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; scriptUrl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;async &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// to preserve execution order&lt;/span&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;head&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figcaption class=&quot;compare__caption&quot;&gt;
&lt;p&gt;To allow execution of this script, the hash of the inline
script must be calculated and added to the CSP response header, replacing the
&lt;code&gt;{HASHED_INLINE_SCRIPT}&lt;/code&gt; placeholder. To reduce the amount of hashes, you can
optionally merge all inline scripts into a single script. To see this in action
checkout the &lt;a href=&quot;https://strict-csp-codelab.glitch.me/solution_hash_csp#&quot; rel=&quot;noopener&quot;&gt;example&lt;/a&gt;
and examine the
&lt;a href=&quot;https://glitch.com/edit/#!/strict-csp-codelab?path=demo%2Fsolution_hash_csp.html%3A1%3A&quot; rel=&quot;noopener&quot;&gt;code&lt;/a&gt;.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Gotchas&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; When calculating a CSP hash for inline scripts, whitespace characters between the opening and closing &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags matter. You can calculate CSP hashes for inline scripts using this &lt;a href=&quot;https://strict-csp-codelab.glitch.me/csp_sha256_util.html&quot;&gt;tool&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h4 id=&quot;script-loading-considerations&quot;&gt;Script loading considerations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#script-loading-considerations&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In the code snippet above, &lt;code&gt;s.async = false&lt;/code&gt; is added to ensure that foo
executes before bar (even if bar loads first). &lt;strong&gt;In this snippet, &lt;code&gt;s.async = false&lt;/code&gt; does not block the parser while the scripts load&lt;/strong&gt;; that&#39;s because the
scripts are added dynamically. The parser will only stop as the scripts are
being executed, just like it would behave for &lt;code&gt;async&lt;/code&gt; scripts. However, with
this snippet, keep in mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One/both scripts may execute before the document has finished downloading. If
you want the document to be ready by the time the scripts execute, you need
to wait for the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Window/DOMContentLoaded_event&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;DOMContentLoaded&lt;/code&gt;
event&lt;/a&gt;
before you append the scripts. If this causes a performance issue (because
the scripts don&#39;t start downloading early enough), you can use &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Preloading_content&quot; rel=&quot;noopener&quot;&gt;preload
tags&lt;/a&gt;
earlier in the page.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defer = true&lt;/code&gt; won&#39;t do anything. If you need that behaviour, you&#39;ll have to
manually run the script at the time you want to run it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;h3 id=&quot;step-3-refactor-html-templates-and-client-side-code-to-remove-patterns-incompatible-with-csp&quot;&gt;Step 3:  Refactor HTML templates and client-side code to remove patterns incompatible with CSP &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#step-3-refactor-html-templates-and-client-side-code-to-remove-patterns-incompatible-with-csp&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Inline event handlers (such as &lt;code&gt;onclick=&amp;quot;…&amp;quot;&lt;/code&gt;, &lt;code&gt;onerror=&amp;quot;…&amp;quot;&lt;/code&gt;) and JavaScript URIs
(&lt;code&gt;&amp;lt;a href=&amp;quot;javascript:…&amp;quot;&amp;gt;&lt;/code&gt;) can be used to run scripts. This means that an
attacker who finds an XSS bug could inject this kind of HTML and execute
malicious JavaScript. A nonce- or hash-based CSP disallows the use of such
markup. If your site makes use of any of the patterns described above, you&#39;ll
need to refactor them into safer alternatives.&lt;/p&gt;
&lt;p&gt;If you enabled CSP in the previous step, you&#39;ll be able to see CSP violations in
the console every time CSP blocks an incompatible pattern.&lt;/p&gt;
&lt;img alt=&quot;CSP violation reports in the Chrome developer console.&quot; decoding=&quot;async&quot; height=&quot;235&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/vgdbNJBYHma2o62ZqYmcnkq3j0o1/mRWfNxAhQXzInOLCgtv8.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;In most cases, the fix is straightforward:&lt;/p&gt;
&lt;h4 id=&quot;to-refactor-inline-event-handlers,-rewrite-them-to-be-added-from-a-javascript-block&quot;&gt;To refactor inline event handlers, rewrite them to be added from a JavaScript block &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#to-refactor-inline-event-handlers,-rewrite-them-to-be-added-from-a-javascript-block&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;worse&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Blocked by CSP&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;onclick&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value javascript language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;doThings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;A thing.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figcaption class=&quot;compare__caption&quot;&gt;
&lt;p&gt;CSP will block inline event handlers.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;better&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Allowed by CSP&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;things&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;A thing.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nonce&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;${nonce}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;things&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; doThings&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figcaption class=&quot;compare__caption&quot;&gt;
&lt;p&gt;CSP will allow event handlers that are registered via JavaScript.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 id=&quot;for-javascript-uris,-you-can-use-a-similar-pattern&quot;&gt;For &lt;code&gt;javascript:&lt;/code&gt; URIs, you can use a similar pattern &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#for-javascript-uris,-you-can-use-a-similar-pattern&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;worse&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Blocked by CSP&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;javascript:linkClicked()&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;foo&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figcaption class=&quot;compare__caption&quot;&gt;
&lt;p&gt;CSP will block javascript: URIs.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;better&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Allowed by CSP&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;foo&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;foo&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nonce&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;${nonce}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;foo&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; linkClicked&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figcaption class=&quot;compare__caption&quot;&gt;
&lt;p&gt;CSP will allow event handlers that are registered via JavaScript.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 id=&quot;use-of-eval-in-javascript&quot;&gt;Use of &lt;code&gt;eval()&lt;/code&gt; in JavaScript &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#use-of-eval-in-javascript&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;If your application uses &lt;code&gt;eval()&lt;/code&gt; to convert JSON string serializations into JS
objects, you should refactor such instances to &lt;code&gt;JSON.parse()&lt;/code&gt;, which is also
&lt;a href=&quot;https://v8.dev/blog/cost-of-javascript-2019#json&quot; rel=&quot;noopener&quot;&gt;faster&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you cannot remove all uses of &lt;code&gt;eval()&lt;/code&gt;, you can still set a strict
nonce-based CSP, but you will have to use the &lt;code&gt;&#39;unsafe-eval&#39;&lt;/code&gt; CSP keyword which
will make your policy slightly less secure.&lt;/p&gt;
&lt;p&gt;You can find these and more examples of such refactoring in this strict CSP
Codelab:&lt;/p&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 420px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/strict-csp-codelab?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=demo%2Fsolution_nonce_csp.html&amp;highlights=14%2C20%2C28%2C39%2C40%2C41%2C42%2C43%2C44%2C45%2C54%2C55%2C56%2C57%2C58%2C59%2C60&amp;previewSize=35&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;strict-csp-codelab on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3 id=&quot;step-4-optional-add-fallbacks-to-support-old-browser-versions&quot;&gt;Step 4 (Optional):  Add fallbacks to support old browser versions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#step-4-optional-add-fallbacks-to-support-old-browser-versions&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Strict CSP (in particular the &lt;code&gt;&#39;strict-dynamic&#39;&lt;/code&gt; keyword) is supported by all browser enigines, so there is no need to add fallbacks to your CSP unless you need to support users on outdated browser versions (see version details below). While setting fallbacks doesn&#39;t reduce the security of your policy in modern browsers, they can lead to confusion as many developers are not familar with the complex CSP fallback mechanisms. &lt;/div&gt;&lt;/aside&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 52, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      52
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 52, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      52
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 15.4, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      15.4
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#strict-dynamic#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;If you need to support browser versions older than the one listed above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Using &lt;code&gt;&#39;strict-dynamic&#39;&lt;/code&gt; requires adding &lt;code&gt;https:&lt;/code&gt; as a fallback for old
versions of Safari. By doing so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All browsers that support &lt;code&gt;&#39;strict-dynamic&#39;&lt;/code&gt; will ignore the &lt;code&gt;https:&lt;/code&gt;
fallback, so this won&#39;t reduce the strength of the policy.&lt;/li&gt;
&lt;li&gt;In old browser, externally sourced scripts will be allowed to load only if
they come from an HTTPS origin. This is less secure than a strict CSP–it&#39;s
a fallback–but would still prevent certain common XSS causes like injections
of &lt;code&gt;javascript:&lt;/code&gt; URIs because &lt;code&gt;&#39;unsafe-inline&#39;&lt;/code&gt; is not present or ignored
in presence of a hash or nonce.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To ensure compatibility with very old browser versions (4+ years), you can add
&lt;code&gt;&#39;unsafe-inline&#39;&lt;/code&gt; as a fallback. All recent browsers will ignore
&lt;code&gt;&#39;unsafe-inline&#39;&lt;/code&gt; if a CSP nonce or hash is present.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Content-Security-Policy:&lt;br /&gt;  script-src &#39;nonce-{random}&#39; &#39;strict-dynamic&#39; https: &#39;unsafe-inline&#39;;&lt;br /&gt;  object-src &#39;none&#39;;&lt;br /&gt;  base-uri &#39;none&#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; &lt;code&gt;https:&lt;/code&gt; and &lt;code&gt;unsafe-inline&lt;/code&gt; don&#39;t make your policy less safe because they will be ignored by all modern browsers which support &lt;code&gt;strict-dynamic&lt;/code&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;step-5-deploy-your-csp&quot;&gt;Step 5:  Deploy your CSP &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#step-5-deploy-your-csp&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After confirming that no legitimate scripts are being blocked by CSP in your
local development environment, you can proceed with deploying your CSP to your
(staging, then) production environment:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;(Optional) Deploy your CSP in report-only mode using the
&lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt; header. Learn more about the &lt;a href=&quot;https://web.dev/reporting-api&quot;&gt;Reporting
API&lt;/a&gt;.
Report-only mode is handy to test a potentially breaking change like a new
CSP in production, before actually enforcing CSP restrictions. In report-only
mode, your CSP does not affect the behavior of your application (nothing will
actually break). But the browser will still generate console errors and
violation reports when patterns incompatible with CSP are encountered (so you
can see what would have broken for your end-users).&lt;/li&gt;
&lt;li&gt;Once you&#39;re confident that your CSP won&#39;t induce breakage for your end-users,
deploy your CSP using the &lt;code&gt;Content-Security-Policy&lt;/code&gt; response header. &lt;strong&gt;Only
once you&#39;ve completed this step, will CSP begin to protect your application
from XSS&lt;/strong&gt;. Setting your CSP via a HTTP header server-side is more secure
than setting it as a &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tag; use a header if you can.&lt;/li&gt;
&lt;/ol&gt;
&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Gotchas&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Make sure that the CSP you&#39;re using is &amp;quot;strict&amp;quot; by checking it with the &lt;a href=&quot;https://csp-evaluator.withgoogle.com/&quot;&gt;CSP Evaluator&lt;/a&gt; or Lighthouse. This is very important, as even small changes to a policy can significantly reduce its security. &lt;/div&gt;&lt;/aside&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; When enabling CSP for production traffic, you may see some noise in the CSP violation reports due to browser extensions and malware. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;limitations&quot;&gt;Limitations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#limitations&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Generally speaking, a strict CSP provides a strong added layer of security that
helps to mitigate XSS. In most cases, CSP reduces the attack surface
significantly (dangerous patterns like &lt;code&gt;javascript:&lt;/code&gt; URIs are completely turned
off). However, based on the type of CSP you&#39;re using (nonces, hashes, with or
without &lt;code&gt;&#39;strict-dynamic&#39;&lt;/code&gt;), there are cases where CSP doesn&#39;t protect:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you nonce a script, but there&#39;s an injection directly into the body or into
the &lt;code&gt;src&lt;/code&gt; parameter of that &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;If there are injections into the locations of dynamically created scripts
(&lt;code&gt;document.createElement(&#39;script&#39;)&lt;/code&gt;), including into any library functions
which create &lt;code&gt;script&lt;/code&gt; DOM nodes based on the value of their arguments. This
includes some common APIs such as jQuery&#39;s &lt;code&gt;.html()&lt;/code&gt;, as well as &lt;code&gt;.get()&lt;/code&gt; and
&lt;code&gt;.post()&lt;/code&gt; in jQuery &amp;lt; 3.0.&lt;/li&gt;
&lt;li&gt;If there are template injections in old AngularJS applications. An attacker
who can inject an AngularJS template can use it to &lt;a href=&quot;https://sites.google.com/site/bughunteruniversity/nonvuln/angularjs-expression-sandbox-bypass&quot; rel=&quot;noopener&quot;&gt;execute arbitrary
JavaScript&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If the policy contains &lt;code&gt;&#39;unsafe-eval&#39;&lt;/code&gt;, injections into &lt;code&gt;eval()&lt;/code&gt;,
&lt;code&gt;setTimeout()&lt;/code&gt; and a few other rarely used APIs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Developers and security engineers should pay particular attention to such
patterns during code reviews and security audits. You can find more details on
the cases described above in &lt;a href=&quot;https://static.sched.com/hosted_files/locomocosec2019/db/CSP%20-%20A%20Successful%20Mess%20Between%20Hardening%20and%20Mitigation%20%281%29.pdf#page=27&quot; rel=&quot;noopener&quot;&gt;this CSP
presentation&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Trusted Types complements strict CSP very well and can efficiently protect against some of the limitations listed above. Learn more about &lt;a href=&quot;https://web.dev/trusted-types&quot;&gt;how to use Trusted Types at web.dev&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further reading &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/strict-csp/#further-reading&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://research.google/pubs/pub45542/&quot; rel=&quot;noopener&quot;&gt;CSP Is Dead, Long Live CSP! On the Insecurity of Whitelists and the Future of
Content Security Policy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://csp-evaluator.withgoogle.com/&quot; rel=&quot;noopener&quot;&gt;CSP Evaluator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://static.sched.com/hosted_files/locomocosec2019/db/CSP%20-%20A%20Successful%20Mess%20Between%20Hardening%20and%20Mitigation%20%281%29.pdf&quot; rel=&quot;noopener&quot;&gt;LocoMoco Conference: Content Security Policy - A successful mess between
hardening and
mitigation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webappsec.dev/assets/pub/Google_IO-Securing_Web_Apps_with_Modern_Platform_Features.pdf&quot; rel=&quot;noopener&quot;&gt;Google I/O talk: Securing Web Apps with Modern Platform
Features&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Lukas Weichselbaum</name>
    </author>
  </entry>
  
  <entry>
    <title>Protect your resources from web attacks with Fetch Metadata</title>
    <link href="https://web.dev/fetch-metadata/"/>
    <updated>2020-06-04T00:00:00Z</updated>
    <id>https://web.dev/fetch-metadata/</id>
    <content type="html" mode="escaped">&lt;h2 id=&quot;why-should-you-care-about-isolating-your-web-resources&quot;&gt;Why should you care about isolating your web resources? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#why-should-you-care-about-isolating-your-web-resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many web applications are vulnerable to &lt;a href=&quot;https://web.dev/same-site-same-origin/#%22same-origin%22-and-%22cross-origin%22&quot;&gt;cross-origin&lt;/a&gt; attacks like &lt;a href=&quot;https://portswigger.net/web-security/csrf&quot; rel=&quot;noopener&quot;&gt;cross-site request forgery&lt;/a&gt; (CSRF), &lt;a href=&quot;https://portswigger.net/research/json-hijacking-for-the-modern-web&quot; rel=&quot;noopener&quot;&gt;cross-site script inclusion&lt;/a&gt; (XSSI), timing attacks, &lt;a href=&quot;https://arxiv.org/pdf/1908.02204.pdf&quot; rel=&quot;noopener&quot;&gt;cross-origin information leaks&lt;/a&gt; or speculative execution side-channel (&lt;a href=&quot;https://developer.chrome.com/blog/meltdown-spectre/&quot; rel=&quot;noopener&quot;&gt;Spectre&lt;/a&gt;) attacks.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/fetch-metadata/&quot; rel=&quot;noopener&quot;&gt;Fetch Metadata&lt;/a&gt; request headers allow you to deploy a strong defense-in-depth mechanism—a Resource Isolation Policy—to protect your application against these common cross-origin attacks.&lt;/p&gt;
&lt;p&gt;It is common for resources exposed by a given web application to only be loaded by the application itself, and not by other websites. In such cases, deploying a Resource Isolation Policy based on Fetch Metadata request headers takes little effort, and at the same time protects the application from cross-site attacks.&lt;/p&gt;
&lt;h2 id=&quot;compatibility&quot;&gt;Browser compatibility &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#compatibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Fetch Metadata request headers are supported in all modern browser engines.&lt;/p&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 76, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      76
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 90, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      90
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 16.4, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      16.4
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Sec-Fetch-Site#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;background&quot;&gt;Background &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#background&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many cross-site attacks are possible because the web is open by default and your application server cannot easily protect itself from communication originating from external applications.
A typical cross-origin attack is cross-site request forgery (CSRF) where an attacker lures a user onto a site they control and then submits a form to the server the user is logged in to. Since the server cannot tell if the request originated from another domain (cross-site) and the browser automatically attaches cookies to cross-site requests, the server will execute the action requested by the attacker on behalf of the user.&lt;/p&gt;
&lt;p&gt;Other cross-site attacks like cross-site script inclusion (XSSI) or cross-origin information leaks are similar in nature to CSRF and rely on loading resources from a victim application in an attacker-controlled document and leaking information about the victim applications. Since applications cannot easily distinguish trusted requests from untrusted ones, they cannot discard malicious cross-site traffic.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Gotchas&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Apart from attacks on resources as described above, &lt;em&gt;window references&lt;/em&gt; can also lead to cross-origin information leaks and Spectre attacks. You can prevent them by setting the &lt;code&gt;Cross-Origin-Opener-Policy&lt;/code&gt; response header to &lt;code&gt;same-origin&lt;/code&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introducing Fetch Metadata &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#introduction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Fetch Metadata request headers are a new web platform security feature designed to help servers defend themselves against cross-origin attacks. By providing information about the context of an HTTP request in a set of &lt;code&gt;Sec-Fetch-*&lt;/code&gt; headers, they allow the responding server to apply security policies before processing the request. This lets developers decide whether to accept or reject a request based on the way it was made and the context in which it will be used, making it possible to respond to only legitimate requests made by their own application.&lt;/p&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;better&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Same-Origin&lt;/p&gt;
&lt;figcaption class=&quot;compare__caption&quot;&gt;
&lt;p&gt;Requests originating from sites served by your own server (same-origin) will continue to work.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;!--lint disable no-literal-urls--&gt;
&lt;img alt=&quot;A fetch request from https://site.example for the resource https://site.example/foo.json in JavaScript causes the browser to send the HTTP request header &amp;#x27;Sec Fetch-Site: same-origin&amp;#x27;.&quot; decoding=&quot;async&quot; height=&quot;176&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/aRsy2xULTR4TM2sMMsbQ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;!--lint enable no-literal-urls--&gt;
&lt;/figure&gt;
&lt;figure class=&quot;compare flow&quot; data-type=&quot;worse&quot; data-size=&quot;full&quot;&gt;&lt;p class=&quot;compare__label&quot;&gt;Cross-site&lt;/p&gt;
&lt;figcaption class=&quot;compare__caption&quot;&gt;
&lt;p&gt;Malicious cross-site requests can be rejected by the server because of the additional context in the HTTP request provided by &lt;code&gt;Sec-Fetch-*&lt;/code&gt; headers.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;!--lint disable no-literal-urls--&gt;
&lt;img alt=&quot;An image on https://evil.example that has set the src attribute of an img element to &amp;#x27;https://site.example/foo.json&amp;#x27; causes the browser to send the HTTP request header &amp;#x27;Sec-Fetch-Site: cross-site&amp;#x27;.&quot; decoding=&quot;async&quot; height=&quot;171&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/xY4yB36JqsVw62wNMIWt.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;!--lint enable no-literal-urls--&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;sec-fetch-site&quot;&gt;&lt;code&gt;Sec-Fetch-Site&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#sec-fetch-site&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 76, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      76
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 90, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      90
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 16.4, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      16.4
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Sec-Fetch-Site#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Sec-Fetch-Site&lt;/code&gt; tells the server which &lt;a href=&quot;https://web.dev/same-site-same-origin&quot;&gt;site&lt;/a&gt; sent the request. The browser sets this value to one of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;same-origin&lt;/code&gt;, if the request was made by your own application (e.g. &lt;code&gt;site.example&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;same-site&lt;/code&gt;, if the request was made by a subdomain of your site (e.g. &lt;code&gt;bar.site.example&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;none&lt;/code&gt;, if the request was explicitly caused by a user&#39;s interaction with the user agent (e.g. clicking on a bookmark)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cross-site&lt;/code&gt;, if the request was sent by another website (e.g. &lt;code&gt;evil.example&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;sec-fetch-mode&quot;&gt;&lt;code&gt;Sec-Fetch-Mode&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#sec-fetch-mode&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 76, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      76
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 90, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      90
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 16.4, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      16.4
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Sec-Fetch-Mode#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Sec-Fetch-Mode&lt;/code&gt; indicates the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Request/mode&quot; rel=&quot;noopener&quot;&gt;mode&lt;/a&gt; of the request. This roughly corresponds to the type of the request and allows you to distinguish resource loads from navigation requests. For example, a destination of &lt;code&gt;navigate&lt;/code&gt; indicates a top-level navigation request while &lt;code&gt;no-cors&lt;/code&gt; indicates resource requests like loading an image.&lt;/p&gt;
&lt;h3 id=&quot;sec-fetch-dest&quot;&gt;&lt;code&gt;Sec-Fetch-Dest&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#sec-fetch-dest&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 80, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      80
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 90, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      90
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 80, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      80
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 16.4, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      16.4
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Sec-Fetch-Dest#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Sec-Fetch-Dest&lt;/code&gt; exposes a request&#39;s &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Request/destination&quot; rel=&quot;noopener&quot;&gt;destination&lt;/a&gt; (e.g. if a &lt;code&gt;script&lt;/code&gt; or an &lt;code&gt;img&lt;/code&gt; tag caused a resource to be requested by the browser).&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-fetch-metadata-to-protect-against-cross-origin-attacks&quot;&gt;How to use Fetch Metadata to protect against cross-origin attacks &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#how-to-use-fetch-metadata-to-protect-against-cross-origin-attacks&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The extra information these request headers provide is quite simple, but the additional context allows you to build powerful security logic on the server-side, also referred to as a Resource Isolation Policy, with just a few lines of code.&lt;/p&gt;
&lt;h3 id=&quot;implementing-a-resource-isolation-policy&quot;&gt;Implementing a Resource Isolation Policy &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#implementing-a-resource-isolation-policy&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A Resource Isolation Policy prevents your resources from being requested by external websites. Blocking such traffic mitigates common cross-site web vulnerabilities such as CSRF, XSSI, timing attacks, and cross-origin information leaks. This policy can be enabled for all endpoints of your application and will allow all resource requests coming from your own application as well as direct navigations (via an HTTP &lt;code&gt;GET&lt;/code&gt; request). Endpoints that are supposed to be loaded in a cross-site context (e.g. endpoints loaded using CORS) can be opted out of this logic.&lt;/p&gt;
&lt;h4 id=&quot;step-1-allow-requests-from-browsers-which-dont-send-fetch-metadata&quot;&gt;Step 1: Allow requests from browsers which don&#39;t send Fetch Metadata &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#step-1-allow-requests-from-browsers-which-dont-send-fetch-metadata&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Since not all browsers support Fetch Metadata, you need to allow requests that don&#39;t set &lt;code&gt;Sec-Fetch-*&lt;/code&gt; headers by checking for the presence of &lt;code&gt;sec-fetch-site&lt;/code&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; All of the following examples are Python code. &lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sec-fetch-site&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Allow this request&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;step-2-allow-same-site-and-browser-initiated-requests&quot;&gt;Step 2: Allow same-site and browser-initiated requests &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#step-2-allow-same-site-and-browser-initiated-requests&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Any requests that do not originate from a cross-origin context (like &lt;code&gt;evil.example&lt;/code&gt;) will be allowed. In particular, these are requests that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Originate from your own application (e.g. a same-origin request where &lt;code&gt;site.example&lt;/code&gt; requests &lt;code&gt;site.example/foo.json&lt;/code&gt; will always be allowed).&lt;/li&gt;
&lt;li&gt;Originate from your subdomains.&lt;/li&gt;
&lt;li&gt;Are explicitly caused by a user&#39;s interaction with the user agent (e.g. direct navigation or by clicking a bookmark, etc.).&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sec-fetch-site&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;same-origin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;same-site&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;none&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Allow this request&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Gotchas&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; In case your subdomains are not fully trusted, you can make the policy stricter by blocking requests from subdomains by removing the &lt;code&gt;same-site&lt;/code&gt; value. &lt;/div&gt;&lt;/aside&gt;
&lt;h4 id=&quot;step-3-allow-simple-top-level-navigation-and-iframing&quot;&gt;Step 3: Allow simple top-level navigation and iframing &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#step-3-allow-simple-top-level-navigation-and-iframing&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To ensure that your site can still be linked from other sites, you have to allow simple (&lt;code&gt;HTTP GET&lt;/code&gt;) top-level navigation.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sec-fetch-mode&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;navigate&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;and&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;method &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;GET&#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# &amp;lt;object&gt; and &amp;lt;embed&gt; send navigation requests, which we disallow.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;and&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sec-fetch-dest&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;object&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;embed&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Allow this request&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Gotchas&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; The logic above protects your application&#39;s endpoints from being used as resources by other websites, but will permit top-level navigation and embedding (e.g. loading in an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;). To further improve security, you can use Fetch Metadata headers to restrict cross-site navigations to only an allowed set of pages. &lt;/div&gt;&lt;/aside&gt;
&lt;h4 id=&quot;step-4-opt-out-endpoints-that-are-meant-to-serve-cross-site-traffic-optional&quot;&gt;Step 4: Opt out endpoints that are meant to serve cross-site traffic (Optional) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#step-4-opt-out-endpoints-that-are-meant-to-serve-cross-site-traffic-optional&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In some cases, your application might provide resources which are meant to be loaded cross-site. These resources need to be exempted on a per-path or per-endpoint basis. Examples of such endpoints are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Endpoints meant to be accessed cross-origin: If your application is serving endpoints that are &lt;code&gt;CORS&lt;/code&gt; enabled, you need to explicitly opt them out from resource isolation to ensure that cross-site requests to these endpoints are still possible.&lt;/li&gt;
&lt;li&gt;Public resources (e.g. images, styles, etc.): Any public and unauthenticated resources that should be loadable cross-origin from other sites can be exempted as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;path &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/my_CORS_endpoint&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/favicon.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Before opting out parts of your application from these security restrictions, make sure they are static and don&#39;t contain any sensitive user information. &lt;/div&gt;&lt;/aside&gt;
&lt;h4 id=&quot;step-5-reject-all-other-requests-that-are-cross-site-and-not-navigational&quot;&gt;Step 5: Reject all other requests that are cross-site and not navigational &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#step-5-reject-all-other-requests-that-are-cross-site-and-not-navigational&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Any other &lt;strong&gt;cross-site&lt;/strong&gt; request will be rejected by this Resource Isolation Policy and thus protect your application from common cross-site attacks.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Gotchas&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; By default, requests violating your policy should be rejected with an &lt;code&gt;HTTP 403&lt;/code&gt; response. But, depending on your use case, you can also consider other actions, such as: - &lt;strong&gt;Only logging violations&lt;/strong&gt;. This is especially useful when testing the compatibility of the policy and finding endpoints that might need to be opted out. - &lt;strong&gt;Modifying the request&lt;/strong&gt;. In certain scenarios, consider performing other actions like redirecting to your landing page and dropping authentication credentials (e.g. cookies). However, be aware that this could weaken the protections of a Fetch Metadata-based policy. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; The following code demonstrates a complete implementation of a robust Resource Isolation Policy on the server or as a middleware to deny potentially malicious cross-site resource requests, while allowing simple navigational requests:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Reject cross-origin requests to protect from CSRF, XSSI, and other bugs&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;allow_request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# Allow requests from browsers which don&#39;t send Fetch Metadata&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sec-fetch-site&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# Allow same-site and browser-initiated requests&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sec-fetch-site&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;same-origin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;same-site&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;none&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# Allow simple top-level navigations except &amp;lt;object&gt; and &amp;lt;embed&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sec-fetch-mode&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;navigate&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;and&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;method &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;GET&#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;and&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sec-fetch-dest&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;object&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;embed&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# [OPTIONAL] Exempt paths/endpoints meant to be served cross-origin.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;path &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/my_CORS_endpoint&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/favicon.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# Reject all other requests that are cross-site and not navigational&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;deploying-a-resource-isolation-policy&quot;&gt;Deploying a Resource Isolation Policy &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#deploying-a-resource-isolation-policy&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Install a module like the code snippet from above to log and monitor how your site behaves and make sure the restrictions don&#39;t affect any legitimate traffic.&lt;/li&gt;
&lt;li&gt;Fix potential violations by exempting legitimate cross-origin endpoints.&lt;/li&gt;
&lt;li&gt;Enforce the policy by dropping non-compliant requests.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;identifying-and-fixing-policy-violations&quot;&gt;Identifying and fixing policy violations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#identifying-and-fixing-policy-violations&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It&#39;s recommended that you test your policy in a side-effect free way by first enabling it in reporting mode in your server-side code. Alternatively, you can implement this logic in middleware, or in a reverse proxy which logs any violations that your policy might produce when applied to production traffic.&lt;/p&gt;
&lt;p&gt;From our experience of rolling out a Fetch Metadata Resource Isolation Policy at Google, most applications are by default compatible with such a policy and rarely require exempting endpoints to allow cross-site traffic.&lt;/p&gt;
&lt;h3 id=&quot;enforcing-a-resource-isolation-policy&quot;&gt;Enforcing a Resource Isolation Policy &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#enforcing-a-resource-isolation-policy&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After you&#39;ve checked that your policy doesn&#39;t impact legitimate production traffic, you&#39;re ready to enforce restrictions, guaranteeing that other sites will not be able to request your resources and protecting your users from cross-site attacks.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Make sure that you reject invalid requests before running authentication checks or any other processing of the request to prevent revealing sensitive timing information. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further reading &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/fetch-metadata/#further-reading&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/fetch-metadata/&quot; rel=&quot;noopener&quot;&gt;W3C Fetch Metadata Request Headers specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://secmetadata.appspot.com/&quot; rel=&quot;noopener&quot;&gt;Fetch Metadata Playground&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webappsec.dev/assets/pub/Google_IO-Securing_Web_Apps_with_Modern_Platform_Features.pdf&quot; rel=&quot;noopener&quot;&gt;Google I/O talk: Securing Web Apps with Modern Platform Features&lt;/a&gt; (Slides)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;DDtM9caQ97I&quot; videoStartAt=&quot;1856&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
</content>
    <author>
      <name>Lukas Weichselbaum</name>
    </author>
  </entry>
</feed>
