<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Mike West on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Mike West</name>
  </author>
  <link href="https://web.dev/authors/mikewest/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/lXPOi8zfvtTDXy2kSHVh.jpeg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Mike is a contributor to web.dev</subtitle>
  
  
  <entry>
    <title>Confound malicious middlemen with HTTPS and HTTP Strict transport security</title>
    <link href="https://web.dev/transport-layer-security/"/>
    <updated>2013-02-14T00:00:00Z</updated>
    <id>https://web.dev/transport-layer-security/</id>
    <content type="html" mode="escaped">&lt;p&gt;Given the amount of personal data that flows through the great series of
tubes that is the internet, encryption isn&#39;t something that we can or should
lightly ignore. Modern browsers offer several mechanisms you can use to ensure
that your users&#39; data is secure while in transit: &lt;a href=&quot;https://web.dev/transport-layer-security/#lock-the-cookie-jar&quot;&gt;secure cookies&lt;/a&gt;
and &lt;a href=&quot;https://web.dev/transport-layer-security/#closing-the-open-window&quot;&gt;Strict Transport Security&lt;/a&gt; are two of the
most important. They allow you to seamlessly protect your users, upgrading
their connections to HTTPS, and providing a guarantee that user data is never
sent in the clear.&lt;/p&gt;
&lt;p&gt;Why should you care? Consider this:&lt;/p&gt;
&lt;p&gt;Delivering a web page over an unencrypted HTTP connection is more or less the
same as handing an unsealed envelope to the first person you see on the street
who looks like she&#39;s walking in the direction of the post office. If you&#39;re
lucky, she might take it all the way there herself, or she might hand it off to
the next person she sees who&#39;s headed the right way. That person might do the
same, and so on.&lt;/p&gt;
&lt;p&gt;Most strangers in this impromptu chain are trustworthy, and would never peek at
your open letter or alter it. The more times the letter changes hands, however,
the greater the number of people with complete access to the letter you&#39;re
sending. In the end, it&#39;s quite likely that your letter&#39;s intended recipient
will get &lt;em&gt;something&lt;/em&gt; in the mail, but whether that something is the &lt;em&gt;same&lt;/em&gt;
something that you handed off in the first place is an open question. Maybe you
should have sealed that envelope…&lt;/p&gt;
&lt;h2 id=&quot;middlemen&quot;&gt;Middlemen &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/transport-layer-security/#middlemen&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For better or worse, huge swaths of the internet rely on the trustworthiness of
strangers. Servers aren&#39;t directly connected to each other, but pass requests
and responses along from router to router in an enormous game of Telephone.&lt;/p&gt;
&lt;p&gt;You can see these hops in action with traceroute. The route from my computer to
HTML5Rocks looks something like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;traceroute&lt;/span&gt; html5rocks.com&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;traceroute&lt;/span&gt; to html5rocks.com &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;173.194&lt;/span&gt;.71.102&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;, &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt; hops max, &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; byte packets&lt;br /&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;  router1-lon.linode.com &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;212.111&lt;/span&gt;.33.229&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;0.453&lt;/span&gt; ms&lt;br /&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;212.111&lt;/span&gt;.33.233 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;212.111&lt;/span&gt;.33.233&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;1.067&lt;/span&gt; ms&lt;br /&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;217.20&lt;/span&gt;.44.194 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;217.20&lt;/span&gt;.44.194&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;0.704&lt;/span&gt; ms&lt;br /&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;  google1.lonap.net &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;193.203&lt;/span&gt;.5.136&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;0.804&lt;/span&gt; ms&lt;br /&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;209.85&lt;/span&gt;.255.76 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;209.85&lt;/span&gt;.255.76&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;0.925&lt;/span&gt; ms&lt;br /&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;209.85&lt;/span&gt;.253.94 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;209.85&lt;/span&gt;.253.94&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;1.226&lt;/span&gt; ms&lt;br /&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;209.85&lt;/span&gt;.240.28 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;209.85&lt;/span&gt;.240.28&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;48.714&lt;/span&gt; ms&lt;br /&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;216.239&lt;/span&gt;.47.12 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;216.239&lt;/span&gt;.47.12&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;22.575&lt;/span&gt; ms&lt;br /&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;209.85&lt;/span&gt;.241.193 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;209.85&lt;/span&gt;.241.193&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;36.033&lt;/span&gt; ms&lt;br /&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;72.14&lt;/span&gt;.233.180 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;72.14&lt;/span&gt;.233.180&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;43.222&lt;/span&gt; ms&lt;br /&gt;&lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;72.14&lt;/span&gt;.233.170 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;72.14&lt;/span&gt;.233.170&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;43.242&lt;/span&gt; ms&lt;br /&gt;&lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;  *&lt;br /&gt;&lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;  lb-in-f102.1e100.net &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;173.194&lt;/span&gt;.71.102&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;44.523&lt;/span&gt; ms&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;13 hops isn&#39;t bad, really. However, if I&#39;m sending requests via HTTP, then each
of those intermediate routers has complete access to my requests and to the
servers&#39; responses. All the data is being transferred as unencrypted plaintext,
and any of those intermediaries could act as a &lt;a href=&quot;http://en.wikipedia.org/wiki/Man-in-the-middle_attack&quot; rel=&quot;noopener&quot;&gt;Man in the
Middle&lt;/a&gt;, reading through
my data, or even manipulating it in transit.&lt;/p&gt;
&lt;p&gt;Worse, this sort of interception is virtually undetectable. A maliciously
modified HTTP response looks exactly like a valid response, as no mechanism
exists that would enable you to ensure that the data received is _exactly _the
data sent. If someone decides to &lt;a href=&quot;http://www.ex-parrot.com/pete/upside-down-ternet.html&quot; rel=&quot;noopener&quot;&gt;turn my Internet upside-down for
laughs&lt;/a&gt;, then I&#39;m more or
less out of luck.&lt;/p&gt;
&lt;h2 id=&quot;is-this-a-secure-line&quot;&gt;Is this a secure line? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/transport-layer-security/#is-this-a-secure-line&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Switching from plaintext HTTP to a secured HTTPS connection offers your best
defense against middlemen. HTTPS connections encrypt the entire channel
end-to-end before any data is sent, making it impossible for machines between
you and your destination to read or modify data in transit.&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt=&quot;Chrome&amp;#x27;s Omnibox gives quite a bit of detail about a connection&amp;#x27;s status.&quot; decoding=&quot;async&quot; height=&quot;390&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 578px) 578px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/c3uAMNblwOgLbCmue6Bl.png?auto=format&amp;w=1156 1156w&quot; width=&quot;578&quot; /&gt;
  &lt;figcaption&gt;
  Chrome&#39;s Omnibox gives quite a bit of detail about a connection&#39;s status.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The security HTTPS provides is rooted in the concept of public and private
cryptographic keys. A deep discussion of the details is (happily) well beyond
the scope of this article, but the core premise is fairly straightforward: data
encrypted with a given public key can &lt;em&gt;only&lt;/em&gt; be decrypted with the corresponding
private key. When a browser kicks off an HTTPS handshake to create a secure
channel, the server provides a certificate which gives the browser all the
information necessary in order to verify its identity by checking that the
server is in possession of the proper private key. All communication from that
point forward is encrypted in such a way that proves that requests are delivered
to and responses received from the authenticated server.&lt;/p&gt;
&lt;p&gt;HTTPS, therefore, gives you some assurance that you&#39;re talking to the server you
think you&#39;re talking to, and that no one else is listening in or twiddling bits
on the wire. This kind of encryption is an absolute prerequisite for security on
the web; if your application isn&#39;t currently delivered over HTTPS, it&#39;s
vulnerable to attack. Fix it. Ars Technica has a great &lt;a href=&quot;http://arstechnica.com/security/2009/12/how-to-get-set-with-a-secure-sertificate-for-free/&quot; rel=&quot;noopener&quot;&gt;guide to obtaining and
installing a certificate (for free)&lt;/a&gt;
that I&#39;d recommend you take a look at for technical details. Configuration will
differ from provider to provider and server to server, but the certificate
request process is the same everywhere.&lt;/p&gt;
&lt;h2 id=&quot;secure-by-default&quot;&gt;Secure by default &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/transport-layer-security/#secure-by-default&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once you&#39;ve requested and installed a certificate, make sure your users benefit
from your hard work: migrate your existing users to HTTPS connections
transparently via the magic of HTTP redirection, and ensure that cookies are
&lt;em&gt;only&lt;/em&gt; delivered over secure connections.&lt;/p&gt;
&lt;h3 id=&quot;this-way,-please&quot;&gt;This way, please &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/transport-layer-security/#this-way,-please&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When a user visits &lt;code&gt;http://example.com/&lt;/code&gt;, redirect them to
&lt;code&gt;https://example.com/&lt;/code&gt; by sending a &lt;code&gt;301 Moved Permanently&lt;/code&gt; response with an appropriate &lt;code&gt;Location&lt;/code&gt; header:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; -I http://mkw.st/&lt;br /&gt;HTTP/1.1 &lt;span class=&quot;token number&quot;&gt;301&lt;/span&gt; Moved Permanently&lt;br /&gt;Server: nginx/1.3.7&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;Keep-Alive: &lt;span class=&quot;token assign-left variable&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;br /&gt;Location: https://mkw.st/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can set up this sort of redirection easily in servers like Apache or Nginx.
For example, an Nginx configuration that redirects from &lt;code&gt;http://example.com/&lt;/code&gt;
to &lt;code&gt;https://example.com/&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-apacheconf&quot;&gt;&lt;code class=&quot;language-apacheconf&quot;&gt;server {&lt;br /&gt;    &lt;span class=&quot;token directive-inline property&quot;&gt;listen&lt;/span&gt; [YOUR IP ADDRESS HERE]:80;&lt;br /&gt;    server_name example.com www.example.com;&lt;br /&gt;    location &lt;span class=&quot;token string&quot;&gt;&quot;/&quot;&lt;/span&gt; {&lt;br /&gt;        rewrite &lt;span class=&quot;token regex&quot;&gt;^(.*) https://www.example.com&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt; permanent;&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;lock-the-cookie-jar&quot;&gt;Lock the cookie jar &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/transport-layer-security/#lock-the-cookie-jar&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Cookies give us the ability to provide users with seamless logged-in experiences
over the stateless HTTP protocol. Data stored in cookies, including sensitive
information like session IDs, is sent along with every request, allowing the
server to make sense of which user it&#39;s responding to at the moment. Once we&#39;ve
ensured that users are hitting our site over HTTPS, we should also ensure that
the sensitive data stored in cookies is only ever transferred over a secure
connection, and never sent in the clear.&lt;/p&gt;
&lt;p&gt;Setting a cookie generally involves an HTTP header that looks something like
this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;set-Cookie&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;KEY=VALUE; path=/; expires=Sat, 01-Jan-2022 00:00:00 GMT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can instruct the browser to restrict the cookie&#39;s use to secure sessions by
tacking on a single keyword:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Set-Cookie&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;KEY=VALUE; path=/; expires=Sat, 01-Jan-2022 00:00:00 GMT; secure&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Cookies set with the &lt;strong&gt;secure&lt;/strong&gt; keyword won&#39;t be sent over HTTP, ever.&lt;/p&gt;
&lt;h2 id=&quot;closing-the-open-window&quot;&gt;Closing the open window &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/transport-layer-security/#closing-the-open-window&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Transparent redirection to HTTPS means that the vast majority of the time your
users are on your site, they&#39;ll be using a secure connection. It does, however,
leave a small window of opportunity for attack: the initial HTTP connection is
wide open, vulnerable to &lt;a href=&quot;http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security#Applicability&quot; rel=&quot;noopener&quot;&gt;SSL
stripping&lt;/a&gt;
and related attacks. Given that a man in the middle has complete access to the
initial HTTP request, it can act as a proxy between you and the server, keeping
you on an insecure HTTP connection regardless of the server&#39;s intentions.&lt;/p&gt;
&lt;p&gt;You can mitigate the risk of this class of attack by asking the browser to
enforce &lt;a href=&quot;http://tools.ietf.org/html/rfc6797&quot; rel=&quot;noopener&quot;&gt;HTTP Strict Transport Security
(HSTS)&lt;/a&gt;. Sending the
&lt;code&gt;Strict-Transport-Security&lt;/code&gt; HTTP header instructs the browser to do the HTTP to
HTTPS redirection &lt;em&gt;client-side&lt;/em&gt;, without ever touching the network (this also
happens to be great for performance; the best request is the one you don&#39;t have
to make):&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; -I https://mkw.st/&lt;br /&gt;HTTP/1.1 &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; OK&lt;br /&gt;Server: nginx/1.3.7&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;Strict-Transport-Security: max-age&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2592000&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Browsers that support this header (currently &lt;a href=&quot;http://caniuse.com/#feat=stricttransportsecurity&quot; rel=&quot;noopener&quot;&gt;Firefox, Chrome, and Opera: caniuse has details&lt;/a&gt;)
will make a note that this particular site has requested HTTPS-only access,
meaning that regardless of how a user comes to the site, she&#39;ll be visiting over
HTTPS. Even if she types &lt;a href=&quot;http://example.com/&quot; rel=&quot;noopener&quot;&gt;http://example.com/&lt;/a&gt; into the browser, she&#39;ll end up
on HTTPS without ever making an HTTP connection. Better yet, if the browser
detects an invalid certificate (potentially trying to spoof your server&#39;s
identity), users won&#39;t be allowed to continue on via HTTP; it&#39;s all or nothing,
which is excellent.&lt;/p&gt;
&lt;p&gt;The browser will expire the server&#39;s HSTS status after &lt;code&gt;max-age&lt;/code&gt; seconds
(about a month in this example); set this to something reasonably high.&lt;/p&gt;
&lt;p&gt;You can also ensure that all of an origin&#39;s subdomains are protected by adding
the &lt;code&gt;includeSubDomains&lt;/code&gt; directive to the header:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;$ curl -I https://mkw.st/&lt;br /&gt;&lt;span class=&quot;token response-status&quot;&gt;&lt;span class=&quot;token http-version property&quot;&gt;HTTP/1.1&lt;/span&gt; &lt;span class=&quot;token status-code number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;token reason-phrase string&quot;&gt;OK&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;nginx/1.3.7&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;...&lt;br /&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Strict-Transport-Security&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value hsts languages-hsts&quot;&gt;max-age=2592000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;go-forth,-securely&quot;&gt;Go forth, securely &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/transport-layer-security/#go-forth,-securely&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;HTTPS the only way to be even remotely sure that data you send reaches the
intended recipient intact. You should set up secure connections for your sites
and applications, today. It&#39;s a fairly straightforward process, and will help
keep your customers&#39; data safe. Once you&#39;ve gotten an encrypted channel in
place, you should transparently redirect users to this secure connection
regardless of how they come to your site by sending a 301 HTTP response. Then
make sure that that all your users&#39; sensitive session information uses &lt;em&gt;only&lt;/em&gt;
that secure connection by adding the &lt;strong&gt;secure&lt;/strong&gt; keyword when setting cookies.
Once you&#39;ve done all that, ensure that your users never accidentally fall off
the bus: protect them by ensuring that their browser does the right thing by
sending a &lt;code&gt;Strict-Transport-Security&lt;/code&gt; header.&lt;/p&gt;
&lt;p&gt;Setting up HTTPS isn&#39;t much work, and has huge benefits for your site and its
users. It&#39;s well worth the effort.&lt;/p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/transport-layer-security/#resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.startssl.com/&quot; rel=&quot;noopener&quot;&gt;StartSSL&lt;/a&gt; offers free domain-verified
certificates. You can&#39;t beat free. Stepping up to higher grades of
verification is, of course, both possible and reasonably priced.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ssllabs.com/ssltest/&quot; rel=&quot;noopener&quot;&gt;SSL Server Test&lt;/a&gt;: Once you&#39;ve set up HTTPS
for your servers, verify that you&#39;ve done it right by running it through SSL
Labs&#39; server test. You&#39;ll get a &lt;a href=&quot;https://www.ssllabs.com/ssltest/analyze.html?d=mkw.st&quot; rel=&quot;noopener&quot;&gt;nicely detailed
report&lt;/a&gt; that shows you
whether you&#39;re really up and running.&lt;/li&gt;
&lt;li&gt;Ars Technica&#39;s recent article &lt;a href=&quot;http://arstechnica.com/information-technology/2012/11/securing-your-web-server-with-ssltls/2/&quot; rel=&quot;noopener&quot;&gt;&amp;quot;Securing your Web Server with
SSL/TLS&amp;quot;&lt;/a&gt;
is worth reading for a little more background detail about the nuts and bolts
of setting up a server.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;http://tools.ietf.org/html/rfc6797&quot; rel=&quot;noopener&quot;&gt;HTTP Strict Transport Security specification
(RFC6797)&lt;/a&gt; is worth skimming for all the
technical information about the &lt;code&gt;Strict-Transport-Security&lt;/code&gt; header you could
possibly want.&lt;/li&gt;
&lt;li&gt;Once you really know what you&#39;re doing, one possible next step would be to
advertise that your site should only be reachable via a specific set of
certificates. There&#39;s some work underway at the IETF which would allow you to
do just that via &lt;a href=&quot;http://tools.ietf.org/html/draft-ietf-websec-key-pinning&quot; rel=&quot;noopener&quot;&gt;the &lt;code&gt;Public-Key-Pins&lt;/code&gt; header&lt;/a&gt;;
still early days, but interesting, and worth following.&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Mike West</name>
    </author>
  </entry>
  
  <entry>
    <title>Play safely in sandboxed IFrames</title>
    <link href="https://web.dev/sandboxed-iframes/"/>
    <updated>2013-01-04T00:00:00Z</updated>
    <id>https://web.dev/sandboxed-iframes/</id>
    <content type="html" mode="escaped">&lt;p&gt;Constructing a rich experience on today&#39;s web almost unavoidably involves
embedding components and content over which you have no real control.
Third-party widgets can drive engagement and play a critical role in the overall
user experience, and user-generated content is sometimes even more important
than a site&#39;s native content. Abstaining from either isn&#39;t really an option, but
both increase the risk that Something Bad™ could happen on your site. Each
widget that you embed -- every ad, every social media widget -- is a potential
attack vector for those with malicious intent:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.html5rocks.com/tutorials/security/content-security-policy/&quot; rel=&quot;noopener&quot;&gt;Content Security Policy
(CSP)&lt;/a&gt;
can mitigate the risks associated with both of these types of content by giving
you the ability to whitelist specifically trusted sources of script and other
content. This is a major step in the right direction, but it&#39;s worth noting that
the protection that most CSP directives offer is binary: the resource is
allowed, or it isn&#39;t. There are times when it would be useful to say &amp;quot;I&#39;m not
sure I actually &lt;em&gt;trust&lt;/em&gt; this source of content, but it&#39;s soooo pretty! Embed it
please, Browser, but don&#39;t let it break my site.&amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;least-privilege&quot;&gt;Least Privilege &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/sandboxed-iframes/#least-privilege&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In essence, we&#39;re looking for a mechanism that will allow us to grant content we
embed only the minimum level of capability necessary to do its job. If a widget
doesn&#39;t &lt;em&gt;need&lt;/em&gt; to pop up a new window, taking away access to window.open can&#39;t
hurt. If it doesn&#39;t require Flash, turning off plugin support shouldn&#39;t be a
problem. We&#39;re as secure as we can be if we follow the &lt;a href=&quot;http://en.wikipedia.org/wiki/Principle_of_least_privilege&quot; rel=&quot;noopener&quot;&gt;principle of least
privilege&lt;/a&gt;, and block
each and every feature that isn&#39;t directly relevant to functionality we&#39;d like
to use.  The result is that we no longer have to blindly trust that some piece
of embedded content won&#39;t take advantage of privileges it shouldn&#39;t be using. It
simply won&#39;t have access to the functionality in the first place.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;iframe&lt;/code&gt; elements are the first step toward a good framework for such a solution.
Loading some untrusted component in an &lt;code&gt;iframe&lt;/code&gt; provides a measure of separation
between your application and the content you&#39;d like to load. The framed content
won&#39;t have access to your page&#39;s DOM, or data you&#39;ve stored locally, nor will it
be able to draw to arbitrary positions on the page; it&#39;s limited in scope to the
frame&#39;s outline. The separation isn&#39;t truly robust, however. The contained page
still has a number of options for annoying or malicious behavior: autoplaying
video, plugins, and popups are the tip of the iceberg.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-sandbox&quot; rel=&quot;noopener&quot;&gt;&lt;strong&gt;&lt;code&gt;sandbox&lt;/code&gt;&lt;/strong&gt; attribute of the &lt;code&gt;iframe&lt;/code&gt; element&lt;/a&gt;
gives us just what we need to tighten the restrictions on framed content. We can
instruct the browser to load a specific frame&#39;s content in a low-privilege
environment, allowing only the subset of capabilities necessary to do whatever
work needs doing.&lt;/p&gt;
&lt;h3 id=&quot;twust,-but-verify&quot;&gt;Twust, but verify &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/sandboxed-iframes/#twust,-but-verify&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Twitter&#39;s &amp;quot;Tweet&amp;quot; button is a great example of functionality that can be more
safely embedded on your site via a sandbox. Twitter allows you to &lt;a href=&quot;https://dev.twitter.com/docs/tweet-button#using-an-iframe&quot; rel=&quot;noopener&quot;&gt;embed the
button via an iframe&lt;/a&gt;
with the following code:&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;iframe&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://platform.twitter.com/widgets/tweet_button.html&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&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 css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;130px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;20px&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;&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;iframe&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;p&gt;To figure out what we can lock down, let&#39;s carefully examine what capabilities
the button requires. The HTML that&#39;s loaded into the frame executes a bit of
JavaScript from Twitter&#39;s servers, and generates a popup populated with a
tweeting interface when clicked. That interface needs access to Twitter&#39;s
cookies in order to tie the tweet to the correct account, and needs the ability
to submit the tweeting form. That&#39;s pretty much it; the frame doesn&#39;t need to
load any plugins, it doesn&#39;t need to navigate the top-level window, or any of a
number of other bits of functionality. Since it doesn&#39;t need those privileges,
let&#39;s remove them by sandboxing the frame&#39;s content.&lt;/p&gt;
&lt;p&gt;Sandboxing works on the basis of a whitelist. We begin by removing all
permissions possible, and then turn individual capabilities back on by adding
specific flags to the sandbox&#39;s configuration. For the Twitter widget, we&#39;ve
decided to enable JavaScript, popups, form submission, and twitter.com&#39;s
cookies. We can do so by adding a &lt;code&gt;sandbox&lt;/code&gt; attribute to the &lt;code&gt;iframe&lt;/code&gt; with the
following value:&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;sandbox&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;allow-same-origin allow-scripts allow-popups allow-forms&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&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://platform.twitter.com/widgets/tweet_button.html&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&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 css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;130px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;20px&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;&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;iframe&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;p&gt;That&#39;s it. We&#39;ve given the frame all the capabilities it requires, and the
browser will helpfully deny it access to any of the privileges that we didn&#39;t
explicitly grant it via the &lt;code&gt;sandbox&lt;/code&gt; attribute&#39;s value.&lt;/p&gt;
&lt;h3 id=&quot;granular-control-over-capabilities&quot;&gt;Granular Control over Capabilities &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/sandboxed-iframes/#granular-control-over-capabilities&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We saw a few of the possible sandboxing flags in the example above, let&#39;s now
dig through the inner workings of the attribute in a little more detail.&lt;/p&gt;
&lt;p&gt;Given an iframe with an empty sandbox attribute, the framed document will be fully sandboxed, subjecting it
to the following restrictions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript will not execute in the framed document. This not only includes
JavaScript explicitly loaded via script tags, but also inline event handlers
and javascript: URLs. This also means that content contained in noscript tags
will be displayed, exactly as though the user had disabled script herself.&lt;/li&gt;
&lt;li&gt;The framed document is loaded into a unique origin, which means that all
same-origin checks will fail; unique origins match no other origins ever, not
even themselves. Among other impacts, this means that the document has no
access to data stored in any origin&#39;s cookies or any other storage mechanisms
(DOM storage, Indexed DB, etc.).&lt;/li&gt;
&lt;li&gt;The framed document cannot create new windows or dialogs (via &lt;code&gt;window.open&lt;/code&gt; or
&lt;code&gt;target=&amp;quot;_blank&amp;quot;&lt;/code&gt;, for instance).&lt;/li&gt;
&lt;li&gt;Forms cannot be submitted.&lt;/li&gt;
&lt;li&gt;Plugins will not load.&lt;/li&gt;
&lt;li&gt;The framed document can only navigate itself, not its top-level parent.
Setting &lt;code&gt;window.top.location&lt;/code&gt; will throw an exception, and clicking on link with
&lt;code&gt;target=&amp;quot;_top&amp;quot;&lt;/code&gt; will have no effect.&lt;/li&gt;
&lt;li&gt;Features that trigger automatically (autofocused form elements, autoplaying
videos, etc.) are blocked.&lt;/li&gt;
&lt;li&gt;Pointer lock cannot be obtained.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;seamless&lt;/code&gt; attribute is ignored on &lt;code&gt;iframes&lt;/code&gt; the framed document contains.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is nicely draconian, and a document loaded into a fully sandboxed &lt;code&gt;iframe&lt;/code&gt;
poses very little risk indeed. Of course, it also can&#39;t do much of value: you
might be able to get away with a full sandbox for some static content, but most
of the time you&#39;ll want to loosen things up a bit.&lt;/p&gt;
&lt;p&gt;With the exception of plugins, each of these restrictions can be lifted by
adding a flag to the sandbox attribute&#39;s value. Sandboxed documents can never
run plugins, as plugins are unsandboxed native code, but everything else is fair
game:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;allow-forms&lt;/code&gt;&lt;/strong&gt; allows form submission.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;allow-popups&lt;/code&gt;&lt;/strong&gt; allows (shock!) popups.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;allow-pointer-lock&lt;/code&gt;&lt;/strong&gt; allows (surprise!) pointer lock.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;allow-same-origin&lt;/code&gt;&lt;/strong&gt; allows the document to maintain its origin; pages loaded
from &lt;code&gt;https://example.com/&lt;/code&gt; will retain access to that origin&#39;s data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;allow-scripts&lt;/code&gt;&lt;/strong&gt; allows JavaScript execution, and also allows features to
trigger automatically (as they&#39;d be trivial to implement via JavaScript).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;allow-top-navigation&lt;/code&gt;&lt;/strong&gt; allows the document to break out of the frame by
navigating the top-level window.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these in mind, we can evaluate exactly why we ended up with the specific
set of sandboxing flags in the Twitter example above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;allow-scripts&lt;/code&gt;&lt;/strong&gt; is required, as the page loaded into the frame runs some
JavaScript to deal with user interaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;allow-popups&lt;/code&gt;&lt;/strong&gt; is required, as the button pops up a tweeting form in a new
window.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;allow-forms&lt;/code&gt;&lt;/strong&gt; is required, as the tweeting form should be submittable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;allow-same-origin&lt;/code&gt;&lt;/strong&gt; is necessary, as twitter.com&#39;s cookies would otherwise
be inaccessible, and the user couldn&#39;t log in to post the form.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One important thing to note is that the sandboxing flags applied to a frame also
apply to any windows or frames created in the sandbox. This means that we have
to add &lt;strong&gt;&lt;code&gt;allow-forms&lt;/code&gt;&lt;/strong&gt; to the frame&#39;s sandbox, even though the form only exists
in the window that the frame pops up.&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;sandbox&lt;/code&gt; attribute in place, the widget gets only the permissions it
requires, and capabilities like plugins, top navigation, and pointer lock remain
blocked. We&#39;ve reduced the risk of embedding the widget, with no ill-effects.
It&#39;s a win for everyone concerned.&lt;/p&gt;
&lt;h2 id=&quot;privilege-separation&quot;&gt;Privilege Separation &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/sandboxed-iframes/#privilege-separation&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sandboxing third-party content in order to run their untrusted code in a
low-privilege environment is fairly obviously beneficial. But what about your
own code? You trust yourself, right? So why worry about sandboxing?&lt;/p&gt;
&lt;p&gt;I&#39;d turn that question around: if your code doesn&#39;t need plugins, why give it
access to plugins? At best, it&#39;s a privilege you never use, at worst it&#39;s a
potential vector for attackers to get a foot in the door. Everyone&#39;s code has
bugs, and practically every application is vulnerable to exploitation in one way
or another. Sandboxing your own code means that even if an attacker successfully
subverts your application, they won&#39;t be given &lt;em&gt;full&lt;/em&gt; access to the
application&#39;s origin; they&#39;ll only be able to do things the application could
do. Still bad, but not as bad as it could be.&lt;/p&gt;
&lt;p&gt;You can reduce the risk even further by breaking your application up into
logical pieces and sandboxing each piece with the minimal privilege possible.
This technique is very common in native code: Chrome, for example, breaks itself
into a high-privilege browser process that has access to the local hard-drive
and can make network connections, and many low-privilege renderer processes that
do the heavy lifting of parsing untrusted content. Renderers don&#39;t need to touch
the disk, the browser takes care of giving them all the information they need to
render a page. Even if a clever hacker finds a way to corrupt a renderer, she
hasn&#39;t gotten very far, as the renderer can&#39;t do much of interest on its own:
all high-privilege access must be routed through the browser&#39;s process.
Attackers will need to find several holes in different pieces of the system
order to do any damage, which hugely reduces the risk of successful pwnage.&lt;/p&gt;
&lt;h3 id=&quot;safely-sandboxing-eval&quot;&gt;Safely sandboxing &lt;code&gt;eval()&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/sandboxed-iframes/#safely-sandboxing-eval&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With sandboxing and the
&lt;a href=&quot;https://developer.mozilla.org/docs/DOM/window.postMessage&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;postMessage&lt;/code&gt; API&lt;/a&gt;, the
success of this model is fairly straightforward to apply to the web. Pieces of
your application can live in sandboxed &lt;code&gt;iframe&lt;/code&gt;s, and the parent document can
broker communication between them by posting messages and listening for
responses. This sort of structure ensures that exploits in any one piece of the
app do the minimum damage possible. It also has the advantage of forcing you to
create clear integration points, so you know exactly where you need to be
careful about validating input and output. Let&#39;s walk through a toy example,
just to see how that might work.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/static/demos/evalbox/index.html&quot;&gt;Evalbox&lt;/a&gt; is an exciting application
that takes a string, and evaluates it as JavaScript. Wow, right? Just what
you&#39;ve been waiting for all these long years. It&#39;s a fairly dangerous
application, of course, as allowing arbitrary JavaScript to execute means that any
and all data an origin has to offer is up for grabs. We&#39;ll mitigate the risk of
Bad Things™ happening by ensuring that the code is executed inside of a sandbox,
which makes it quite a bit safer. We&#39;ll work our way through the code from the
inside out, starting with the frame&#39;s contents:&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 comment&quot;&gt;&amp;lt;!-- frame.html --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&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;html&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;head&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;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Evalbox&#39;s Frame&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;title&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;br /&gt;        window&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;message&#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;e&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; mainWindow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;source&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; result &lt;span class=&quot;token operator&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;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&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 keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&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;            result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;eval() threw an exception.&#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;br /&gt;        mainWindow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;postMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;origin&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;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;head&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;html&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;p&gt;Inside the frame, we have a minimal document that simply listens for messages
from its parent by hooking into the &lt;code&gt;message&lt;/code&gt; event of the &lt;code&gt;window&lt;/code&gt; object.
Whenever the parent executes postMessage on the iframe&#39;s contents, this event
will trigger, giving us access to the string our parent would like us to
execute.&lt;/p&gt;
&lt;p&gt;In the handler, we grab the &lt;code&gt;source&lt;/code&gt; attribute of the event, which is the parent
window. We&#39;ll use this to send the result of our hard work back up once we&#39;re
done. Then we&#39;ll do the heavy lifting, by passing the data we&#39;ve been given into
&lt;code&gt;eval()&lt;/code&gt;. This call has been wrapped up in a try block, as banned operations
inside a sandboxed &lt;code&gt;iframe&lt;/code&gt; will frequently generate DOM exceptions; we&#39;ll catch
those and report a friendly error message instead. Finally, we post the result
back to the parent window. This is pretty straightforward stuff.&lt;/p&gt;
&lt;p&gt;The parent is similarly uncomplicated. We&#39;ll create a tiny UI with a &lt;code&gt;textarea&lt;/code&gt;
for code, and a &lt;code&gt;button&lt;/code&gt; for execution, and we&#39;ll pull in &lt;code&gt;frame.html&lt;/code&gt; via a
sandboxed &lt;code&gt;iframe&lt;/code&gt;, allowing only script execution:&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;textarea&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;&#39;&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;&#39;&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;textarea&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;button&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;&#39;&lt;/span&gt;safe&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;eval() in a sandboxed frame.&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;button&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;sandbox&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;&#39;&lt;/span&gt;allow-scripts&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;br /&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;&#39;&lt;/span&gt;sandboxed&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;br /&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;&#39;&lt;/span&gt;frame.html&lt;span class=&quot;token punctuation&quot;&gt;&#39;&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;iframe&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;p&gt;Now we&#39;ll wire things up for execution. First, we&#39;ll listen for responses from
the &lt;code&gt;iframe&lt;/code&gt; and &lt;code&gt;alert()&lt;/code&gt; them to our users. Presumably a real application
would do something less annoying:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;window&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;message&#39;&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;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&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;// Sandboxed iframes which lack the &#39;allow-same-origin&#39;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// header have &quot;null&quot; rather than a valid origin. This means you still&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// have to be careful about accepting data via the messaging API you&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// create. Check that source, and validate those inputs!&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; frame &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;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sandboxed&#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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;origin &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;null&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;amp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;amp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;source &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; frame&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contentWindow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Result: &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Next, we&#39;ll hook up an event handler to clicks on the &lt;code&gt;button&lt;/code&gt;. When the user
clicks, we&#39;ll grab the current contents of the &lt;code&gt;textarea&lt;/code&gt;, and pass them into the
frame for execution:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;evaluate&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;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; frame &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;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sandboxed&#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;var&lt;/span&gt; code &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;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;code&#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;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Note that we&#39;re sending the message to &quot;*&quot;, rather than some specific&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// origin. Sandboxed iframes which lack the &#39;allow-same-origin&#39; header&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// don&#39;t have an origin which you can target: you&#39;ll have to send to any&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// origin, which might alow some esoteric attacks. Validate your output!&lt;/span&gt;&lt;br /&gt;    frame&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contentWindow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;postMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code&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 punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&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;safe&#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;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; evaluate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Easy, right? We&#39;ve created a very simple evaluation API, and we can be sure that
code that&#39;s evaluated doesn&#39;t have access to sensitive information like cookies
or DOM storage. Likewise, evaluated code can&#39;t load plugins, pop up new windows,
or any of a number of other annoying or malicious activities.&lt;/p&gt;
&lt;p&gt;You can do the same for your own code by breaking monolithic applications into
single-purpose components. Each can be wrapped in a simple messaging API, just
like what we&#39;ve written above. The high-privilege parent window can act as a
controller and dispatcher, sending messages into specific modules that each have
the fewest privileges possible to do their jobs, listening for results, and
ensuring that each module is well-fed with only the information it requires.&lt;/p&gt;
&lt;p&gt;Note, however, that you need to be very careful when dealing with framed content
that comes from the same origin as the parent. If a page on
&lt;code&gt;https://example.com/&lt;/code&gt; frames another page on the same origin with a sandbox
that includes both the &lt;strong&gt;allow-same-origin&lt;/strong&gt; and &lt;strong&gt;allow-scripts&lt;/strong&gt; flags, then
the framed page can reach up into the parent, and remove the sandbox attribute
entirely.&lt;/p&gt;
&lt;h2 id=&quot;play-in-your-sandbox&quot;&gt;Play in your sandbox &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/sandboxed-iframes/#play-in-your-sandbox&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sandboxing is available for you now in a variety of browsers: Firefox 17+,
IE10+, and Chrome at the time of writing (&lt;a href=&quot;http://caniuse.com/#feat=iframe-sandbox&quot; rel=&quot;noopener&quot;&gt;caniuse, of course, has an up-to-date
support table&lt;/a&gt;). Applying the &lt;code&gt;sandbox&lt;/code&gt;
attribute to &lt;code&gt;iframes&lt;/code&gt; you include allows you to grant certain privileges to the
content they display, &lt;em&gt;only&lt;/em&gt; those privileges which are necessary for the
content to function correctly. This gives you the opportunity to reduce the risk
associated with the inclusion of third-party content, above and beyond what is
already possible with &lt;a href=&quot;http://www.html5rocks.com/tutorials/security/content-security-policy/&quot; rel=&quot;noopener&quot;&gt;Content Security
Policy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Moreover, sandboxing is a powerful technique for reducing the risk that a clever
attacker will be able to exploit holes in your own code. By separating a
monolithic application into a set of sandboxed services, each responsible for a
small chunk of self-contained functionality, attackers will be forced to not
only compromise specific frames&#39; content, but also their controller. That&#39;s a
much more difficult task, especially since the controller can be greatly reduced
in scope. You can spend your security-related effort auditing &lt;em&gt;that&lt;/em&gt; code if you
ask the browser for help with the rest.&lt;/p&gt;
&lt;p&gt;That&#39;s not to say that sandboxing is a complete solution to the problem of
security on the internet. It offers defense in depth, and unless you have
control over your users&#39; clients, you can&#39;t yet rely on browser support for all
your users (if you do control your users clients -- an enterprise environment,
for example -- hooray!). Someday… but for now sandboxing is another layer of
protection to strengthen your defenses, it&#39;s not a complete defense upon which
you can soley rely. Still, layers are excellent. I suggest making use of this
one.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/sandboxed-iframes/#further-reading&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&amp;quot;&lt;a href=&quot;http://www.cs.berkeley.edu/~devdatta/LeastPrivileges.pdf&quot; rel=&quot;noopener&quot;&gt;Privilege Separation in HTML5 Applications&lt;/a&gt;&amp;quot;
is an interesting paper that works through the design of a small framework,
and its application to three existing HTML5 apps.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sandboxing can be even more flexible when combined with two other new iframe
attributes: &lt;a href=&quot;http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-srcdoc&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;srcdoc&lt;/code&gt;&lt;/a&gt;,
and &lt;a href=&quot;http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-seamless&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;seamless&lt;/code&gt;&lt;/a&gt;.
The former allows you to populate a frame with content without the overhead of
an HTTP request, and the latter allows style to flow into the framed content.
Both have fairly miserable browser support at the moment (Chrome and WebKit
nightlies). but will be an interesting combination in the future. You could,
for example, sandbox comments on an article via the following code:&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;sandbox&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;seamless&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token attr-name&quot;&gt;srcdoc&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;&amp;lt;p&gt;This is a user&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;s comment!&lt;br /&gt;                       It can&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;t execute script!&lt;br /&gt;                       Hooray for safety!&amp;lt;/p&gt;&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;iframe&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;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Mike West</name>
    </author>
  </entry>
  
  <entry>
    <title>Content security policy</title>
    <link href="https://web.dev/csp/"/>
    <updated>2012-06-15T00:00:00Z</updated>
    <id>https://web.dev/csp/</id>
    <content type="html" mode="escaped">&lt;p&gt;The web&#39;s security model is rooted in the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Same-origin_policy&quot; rel=&quot;noopener&quot;&gt;&lt;em&gt;same-origin policy&lt;/em&gt;&lt;/a&gt;. Code
from &lt;code&gt;https://mybank.com&lt;/code&gt; should only have access to &lt;code&gt;https://mybank.com&lt;/code&gt;&#39;s
data, and &lt;code&gt;https://evil.example.com&lt;/code&gt; should certainly never be allowed access.
Each origin is kept isolated from the rest of the web, giving developers a safe
sandbox in which to build and play. In theory, this is perfectly brilliant. In
practice, attackers have found clever ways to subvert the system.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-site_scripting&quot; rel=&quot;noopener&quot;&gt;Cross-site scripting (XSS)&lt;/a&gt;
attacks, for example, bypass the same origin policy by tricking a site into
delivering malicious code along with the intended content. This is a huge
problem, as browsers trust all of the code that shows up on a page as being
legitimately part of that page&#39;s security origin. The
&lt;a href=&quot;https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet&quot; rel=&quot;noopener&quot;&gt;XSS Cheat Sheet&lt;/a&gt;
is an old but representative cross-section of the methods an attacker might use
to violate this trust by injecting malicious code. If an attacker successfully
injects &lt;em&gt;any&lt;/em&gt; code at all, it&#39;s pretty much game over: user session data is
compromised and information that should be kept secret is exfiltrated to The Bad
Guys. We&#39;d obviously like to prevent that if possible.&lt;/p&gt;
&lt;p&gt;This overview highlights a defense that can significantly reduce the risk and
impact of XSS attacks in modern browsers: Content Security Policy (CSP).&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#summary&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Use allowlists to tell the client what&#39;s allowed and what isn&#39;t.&lt;/li&gt;
&lt;li&gt;Learn what directives are available.&lt;/li&gt;
&lt;li&gt;Learn the keywords they take.&lt;/li&gt;
&lt;li&gt;Inline code and &lt;code&gt;eval()&lt;/code&gt; are considered harmful.&lt;/li&gt;
&lt;li&gt;Report policy violations to your server before enforcing them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;source-allowlists&quot;&gt;Source allowlists &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#source-allowlists&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The issue exploited by XSS attacks is the browser&#39;s inability to distinguish
between script that&#39;s part of your application and script that&#39;s been
maliciously injected by a third-party. For example, the Google +1 button at the
bottom of this page loads and executes code from
&lt;code&gt;https://apis.google.com/js/plusone.js&lt;/code&gt; in the context of this page&#39;s origin. We
trust that code, but we can&#39;t expect the browser to figure out on its own that code
from &lt;code&gt;apis.google.com&lt;/code&gt; is awesome, while code from &lt;code&gt;apis.evil.example.com&lt;/code&gt;
probably isn&#39;t. The browser happily downloads and executes any code a page
requests, regardless of source.&lt;/p&gt;
&lt;p&gt;Instead of blindly trusting &lt;em&gt;everything&lt;/em&gt; that a server delivers, CSP defines the
&lt;code&gt;Content-Security-Policy&lt;/code&gt; HTTP header, which allows you to create an allowlist of
sources of trusted content, and instructs the browser to only execute or render
resources from those sources. Even if an attacker can find a hole through which
to inject script, the script won&#39;t match the allowlist, and therefore won&#39;t be
executed.&lt;/p&gt;
&lt;p&gt;Since we trust &lt;code&gt;apis.google.com&lt;/code&gt; to deliver valid code, and we trust ourselves
to do the same, let&#39;s define a policy that only allows script to execute when it
comes from one of those two sources:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Security-Policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value csp languages-csp&quot;&gt;script-src &#39;self&#39; https://apis.google.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Simple, right? As you probably guessed, &lt;code&gt;script-src&lt;/code&gt; is a directive that
controls a set of script-related privileges for a specific page. We&#39;ve specified
&lt;code&gt;&#39;self&#39;&lt;/code&gt; as one valid source of script, and &lt;code&gt;https://apis.google.com&lt;/code&gt; as
another. The browser dutifully downloads and executes JavaScript from
&lt;code&gt;apis.google.com&lt;/code&gt; over HTTPS, as well as from the current page&#39;s origin.&lt;/p&gt;
&lt;div class=&quot;attempt-right&quot;&gt;
  &lt;figure&gt;
    &lt;img alt=&quot;Console error: Refused to load the script &amp;#x27;http://evil.example.com/evil.js&amp;#x27; because it violates the following Content Security Policy directive: script-src &amp;#x27;self&amp;#x27; https://apis.google.com&quot; decoding=&quot;async&quot; height=&quot;173&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 709px) 709px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RSnKHpls9RiDnnSGxMlE.png?auto=format&amp;w=1418 1418w&quot; width=&quot;709&quot; /&gt;
  &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;With this policy defined, the browser simply throws an error instead of
loading script from any other source. When a clever attacker manages to
inject code into your site, they&#39;ll run headlong into an error message rather
than the success they were expecting.&lt;/p&gt;
&lt;h3 id=&quot;policy-applies-to-a-wide-variety-of-resources&quot;&gt;Policy applies to a wide variety of resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#policy-applies-to-a-wide-variety-of-resources&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While script resources are the most obvious security risks, CSP provides a rich
set of policy directives that enable fairly granular control over the resources
that a page is allowed to load. You&#39;ve already seen &lt;code&gt;script-src&lt;/code&gt;, so the concept
should be clear.&lt;/p&gt;
&lt;p&gt;Let&#39;s quickly walk through the rest of the resource directives. The list below
represents the state of the directives as of level 2. A &lt;a href=&quot;https://www.w3.org/TR/CSP3/&quot; rel=&quot;noopener&quot;&gt;level 3
spec&lt;/a&gt; has been published, but is &lt;a href=&quot;https://www.chromestatus.com/features#csp3&quot; rel=&quot;noopener&quot;&gt;largely
unimplemented&lt;/a&gt; in the major
browsers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;base-uri&lt;/code&gt;&lt;/strong&gt; restricts the URLs that can appear in a page&#39;s &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;child-src&lt;/code&gt;&lt;/strong&gt; lists the URLs for workers and embedded frame contents. For
example: &lt;code&gt;child-src https://youtube.com&lt;/code&gt; would enable embedding videos from
YouTube but not from other origins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;connect-src&lt;/code&gt;&lt;/strong&gt; limits the origins that you can connect to (via XHR,
WebSockets, and EventSource).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;font-src&lt;/code&gt;&lt;/strong&gt; specifies the origins that can serve web fonts. Google&#39;s web
fonts could be enabled via &lt;code&gt;font-src https://themes.googleusercontent.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;form-action&lt;/code&gt;&lt;/strong&gt; lists valid endpoints for submission from &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; tags.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;frame-ancestors&lt;/code&gt;&lt;/strong&gt;  specifies the sources that can embed the current page.
This directive applies to &lt;code&gt;&amp;lt;frame&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;embed&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;applet&amp;gt;&lt;/code&gt; tags.
This directive can&#39;t be used in &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tags and applies only to non-HTML
resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;frame-src&lt;/code&gt;&lt;/strong&gt; was deprecated in level 2, but is restored in level 3. If not
present it still falls back to  &lt;code&gt;child-src&lt;/code&gt; as before.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;img-src&lt;/code&gt;&lt;/strong&gt; defines the origins from which images can be loaded.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;media-src&lt;/code&gt;&lt;/strong&gt; restricts the origins allowed to deliver video and audio.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;object-src&lt;/code&gt;&lt;/strong&gt; allows control over Flash and other plugins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;plugin-types&lt;/code&gt;&lt;/strong&gt; limits the kinds of plugins a page may invoke.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;report-uri&lt;/code&gt;&lt;/strong&gt; specifies a URL where a browser will send reports when a
content security policy is violated. This directive can&#39;t be used in &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt;
tags.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;style-src&lt;/code&gt;&lt;/strong&gt; is &lt;code&gt;script-src&lt;/code&gt;&#39;s counterpart for stylesheets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;upgrade-insecure-requests&lt;/code&gt;&lt;/strong&gt; instructs user agents to rewrite URL schemes,
changing HTTP to HTTPS. This directive is for websites with large numbers of
old    URL&#39;s that need to be rewritten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;worker-src&lt;/code&gt;&lt;/strong&gt; is a CSP Level 3 directive that restricts the URLs that may
be loaded as a worker, shared worker, or service worker. As of July 2017, this
directive has
&lt;a href=&quot;https://www.chromestatus.com/features/5922594955984896&quot; rel=&quot;noopener&quot;&gt;limited implementations&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By default, directives are wide open. If you don&#39;t set a specific policy for a
directive, let&#39;s say &lt;code&gt;font-src&lt;/code&gt;, then that directive behaves by default as
though you&#39;d specified &lt;code&gt;*&lt;/code&gt; as the valid source (for example, you could load fonts from
anywhere, without restriction).&lt;/p&gt;
&lt;p&gt;You can override this default behavior by specifying a &lt;strong&gt;&lt;code&gt;default-src&lt;/code&gt;&lt;/strong&gt;
directive. This directive defines the defaults for most
directives that you leave unspecified. Generally, this applies to any directive that
ends with &lt;code&gt;-src&lt;/code&gt;. If &lt;code&gt;default-src&lt;/code&gt; is set to &lt;code&gt;https://example.com&lt;/code&gt;, and you fail
to specify a &lt;code&gt;font-src&lt;/code&gt; directive, then you can load fonts from
&lt;code&gt;https://example.com&lt;/code&gt;, and nowhere else. We specified only &lt;code&gt;script-src&lt;/code&gt; in our
earlier examples, which means that images, fonts, and so on can be loaded from
any origin.&lt;/p&gt;
&lt;p&gt;The following directives don&#39;t use &lt;code&gt;default-src&lt;/code&gt; as a fallback. Remember that
failing to set them is the same as allowing anything.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;base-uri&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;form-action&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;frame-ancestors&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;plugin-types&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;report-uri&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sandbox&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use as many or as few of these directives as makes sense for your
specific application, simply listing each in the HTTP header, separating
directives with semicolons. Make sure that you list &lt;em&gt;all&lt;/em&gt;
required resources of a specific type in a &lt;em&gt;single&lt;/em&gt; directive. If you wrote
something like &lt;code&gt;script-src https://host1.com; script-src https://host2.com&lt;/code&gt; the
second directive would simply be ignored. Something like the following would
correctly specify both origins as valid:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;script-src https://host1.com https://host2.com&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If, for example, you have an application that loads all of its resources from a
content delivery network (say, &lt;code&gt;https://cdn.example.net&lt;/code&gt;), and know that you
don&#39;t need any framed content or plugins, then your policy might look something
like the following:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Security-Policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value csp languages-csp&quot;&gt;default-src https://cdn.example.net; child-src &#39;none&#39;; object-src &#39;none&#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;implementation-details&quot;&gt;Implementation details &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#implementation-details&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You will see &lt;code&gt;X-WebKit-CSP&lt;/code&gt; and &lt;code&gt;X-Content-Security-Policy&lt;/code&gt; headers in various
tutorials on the web. Going forward, you should ignore these prefixed
headers. Modern browsers (with the exception of IE) support the unprefixed
&lt;code&gt;Content-Security-Policy&lt;/code&gt; header. That&#39;s the header you should use.&lt;/p&gt;
&lt;p&gt;Regardless of the header you use, policy is defined on a page-by-page basis:
you&#39;ll need to send the HTTP header along with every response that you&#39;d like to
ensure is protected. This provides a lot of flexibility, as you can fine-tune
the policy for specific pages based on their specific needs. Perhaps one set of
pages in your site has a +1 button, while others don&#39;t: you could allow the
button code to be loaded only when necessary.&lt;/p&gt;
&lt;p&gt;The source list in each directive is flexible. You can specify sources by
scheme (&lt;code&gt;data:&lt;/code&gt;, &lt;code&gt;https:&lt;/code&gt;), or ranging in specificity from hostname-only
(&lt;code&gt;example.com&lt;/code&gt;, which matches any origin on that host: any scheme, any port) to
a fully qualified URI (&lt;code&gt;https://example.com:443&lt;/code&gt;, which matches only HTTPS, only
&lt;code&gt;example.com&lt;/code&gt;, and only port 443). Wildcards are accepted, but only as a scheme,
a port, or in the leftmost position of the hostname: &lt;code&gt;*://*.example.com:*&lt;/code&gt; would
match all subdomains of &lt;code&gt;example.com&lt;/code&gt; (but &lt;em&gt;not&lt;/em&gt; &lt;code&gt;example.com&lt;/code&gt; itself), using
any scheme, on any port.&lt;/p&gt;
&lt;p&gt;The source list also accepts four keywords:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&#39;none&#39;&lt;/code&gt;&lt;/strong&gt;, as you might expect, matches nothing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&#39;self&#39;&lt;/code&gt;&lt;/strong&gt; matches the current origin, but not its subdomains.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&#39;unsafe-inline&#39;&lt;/code&gt;&lt;/strong&gt; allows inline JavaScript and CSS. (We&#39;ll touch on this in
more detail in a bit.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&#39;unsafe-eval&#39;&lt;/code&gt;&lt;/strong&gt; allows text-to-JavaScript mechanisms like &lt;code&gt;eval&lt;/code&gt;. (We&#39;ll get
to this too.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These keywords require single-quotes. For example, &lt;code&gt;script-src &#39;self&#39;&lt;/code&gt; (with quotes)
authorizes the execution of JavaScript from the current host; &lt;code&gt;script-src self&lt;/code&gt;
(no quotes) allows JavaScript from a server named &amp;quot;&lt;code&gt;self&lt;/code&gt;&amp;quot; (and &lt;em&gt;not&lt;/em&gt; from the
current host), which probably isn&#39;t what you meant.&lt;/p&gt;
&lt;h3 id=&quot;sandboxing&quot;&gt;Sandboxing &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#sandboxing&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There&#39;s one more directive worth talking about: &lt;code&gt;sandbox&lt;/code&gt;. It&#39;s a bit
different from the others we&#39;ve looked at, as it places restrictions on actions that
the page can take rather than on resources that the page can load. If the
&lt;code&gt;sandbox&lt;/code&gt; directive is present, the page is treated as though it was loaded
inside of an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; with a &lt;code&gt;sandbox&lt;/code&gt; attribute. This can have a wide range of
effects on the page: forcing the page into a unique origin, and preventing form
submission, among others. It&#39;s a bit beyond the scope of this article, but you
can find full details on valid sandboxing attributes in the
&lt;a href=&quot;https://html.spec.whatwg.org/dev/origin.html#sandboxing&quot; rel=&quot;noopener&quot;&gt;&amp;quot;Sandboxing&amp;quot; section of the HTML5 spec&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-meta-tag&quot;&gt;The meta tag &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#the-meta-tag&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;CSPs preferred delivery mechanism is an HTTP header. It can be useful, however,
to set a policy on a page directly in the markup. Do that using a &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tag with
an &lt;code&gt;http-equiv&lt;/code&gt; attribute:&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;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;http-equiv&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;Content-Security-Policy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&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;default-src https://cdn.example.net; child-src &lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;; object-src &lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This can&#39;t be used for &lt;code&gt;frame-ancestors&lt;/code&gt;, &lt;code&gt;report-uri&lt;/code&gt;, or &lt;code&gt;sandbox&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;inline-code-is-considered-harmful&quot;&gt;Inline code is considered harmful &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#inline-code-is-considered-harmful&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It should be clear that CSP is based on allowlist origins, as that&#39;s an
unambiguous way of instructing the browser to treat specific sets of resources
as acceptable and to reject the rest. Origin-based allowlists don&#39;t,
however, solve the biggest threat posed by XSS attacks: inline script injection.
If an attacker can inject a script tag that directly contains some malicious
payload (&lt;code&gt;&amp;lt;script&amp;gt;sendMyDataToEvilDotCom()&amp;lt;/script&amp;gt;&lt;/code&gt;),
the browser has no mechanism by which to distinguish it from a legitimate
inline script tag. CSP solves this problem by banning inline script entirely:
it&#39;s the only way to be sure.&lt;/p&gt;
&lt;p&gt;This ban includes not only scripts embedded directly in &lt;code&gt;script&lt;/code&gt; tags, but also
inline event handlers and &lt;code&gt;javascript:&lt;/code&gt; URLs. You&#39;ll need to move the content of
&lt;code&gt;script&lt;/code&gt; tags into an external file, and replace &lt;code&gt;javascript:&lt;/code&gt; URLs and &lt;code&gt;&amp;lt;a ... onclick=&amp;quot;[JAVASCRIPT]&amp;quot;&amp;gt;&lt;/code&gt; with appropriate &lt;code&gt;addEventListener()&lt;/code&gt; calls. For example,
you might rewrite the following from:&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;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doAmazingThings&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;    &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;YOU AM AMAZING!&#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 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;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;button&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;&#39;&lt;/span&gt;&lt;span class=&quot;token value javascript language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;doAmazingThings&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;&#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Am I amazing?&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;button&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;p&gt;to something more like:&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 comment&quot;&gt;&amp;lt;!-- amazing.html --&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;&#39;&lt;/span&gt;amazing.js&lt;span class=&quot;token punctuation&quot;&gt;&#39;&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;button&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;&#39;&lt;/span&gt;amazing&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Am I amazing?&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;button&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;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// amazing.js&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doAmazingThings&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;    &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;YOU AM AMAZING!&#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 punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;document&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;DOMContentLoaded&#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 punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&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;amazing&#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; doAmazingThings&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The rewritten code has a number of advantages above and beyond working well with
CSP; it&#39;s already best practice, regardless of your use of CSP. Inline
JavaScript mixes structure and behavior in exactly the way you shouldn&#39;t.
External resources are easier for browsers to cache, more understandable for
developers, and conducive to compilation and minification. You&#39;ll write better
code if you do the work to move code into external resources.&lt;/p&gt;
&lt;p&gt;Inline style is treated in the same way: both the &lt;code&gt;style&lt;/code&gt; attribute and &lt;code&gt;style&lt;/code&gt;
tags should be consolidated into external stylesheets to protect against a
variety of &lt;a href=&quot;https://scarybeastsecurity.blogspot.com/2009/12/generic-cross-browser-cross-domain.html&quot; rel=&quot;noopener&quot;&gt;surprisingly
clever&lt;/a&gt;
data exfiltration methods that CSS enables.&lt;/p&gt;
&lt;p&gt;If you must have inline script and style, you can enable it
by adding &lt;code&gt;&#39;unsafe-inline&#39;&lt;/code&gt; as an allowed source in a &lt;code&gt;script-src&lt;/code&gt; or &lt;code&gt;style-src&lt;/code&gt;
directive. You can also use a nonce or a hash (see below), but you really shouldn&#39;t.
Banning inline script is the biggest security win CSP provides, and
banning inline style likewise hardens your application. It&#39;s a little bit of
effort up front to ensure that things work correctly after moving all the code
out-of-line, but that&#39;s a tradeoff that&#39;s well worth making.&lt;/p&gt;
&lt;h3 id=&quot;if-you-absolutely-must-use-it&quot;&gt;If you absolutely must use it &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#if-you-absolutely-must-use-it&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;CSP Level 2 offers backward compatibility for inline scripts by allowing you to
add specific inline scripts to the allowlist using either a cryptographic nonce (number
used once) or a hash. Although this may be cumbersome, it is useful
in a pinch.&lt;/p&gt;
&lt;p&gt;To use a nonce, give your script tag a nonce attribute. Its value must match one
in the list of trusted sources. For example:&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;EDNnf03nceIOfn39fn3e9h3sdfa&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;    &lt;span class=&quot;token comment&quot;&gt;// Some inline code I can&#39;t remove yet, but need to asap.&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;p&gt;Now, add the nonce to your &lt;code&gt;script-src&lt;/code&gt; directive appended to the &lt;code&gt;nonce-&lt;/code&gt; keyword.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Security-Policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value csp languages-csp&quot;&gt;script-src &#39;nonce-EDNnf03nceIOfn39fn3e9h3sdfa&#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Remember that nonces must be regenerated for every page request and they must be
unguessable.&lt;/p&gt;
&lt;p&gt;Hashes work in much the same way. Instead of adding code to the script tag,
create a SHA hash of the script itself and add it to the &lt;code&gt;script-src&lt;/code&gt; directive.
For example, let&#39;s say your page contained this:&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;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Hello, world.&#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;/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;p&gt;Your policy would contain this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Security-Policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value csp languages-csp&quot;&gt;script-src &#39;sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng=&#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;There are a few things to note here. The &lt;code&gt;sha*-&lt;/code&gt; prefix specifies the algorithm
that generates the hash. In the example above, &lt;code&gt;sha256-&lt;/code&gt; is used. CSP also
supports &lt;code&gt;sha384-&lt;/code&gt; and &lt;code&gt;sha512-&lt;/code&gt;. When generating the hash, do not include the
&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags. Also capitalization and whitespace matter, including leading or
trailing whitespace.&lt;/p&gt;
&lt;p&gt;A Google search on generating SHA hashes will lead you to solutions in any
number of languages. Using Chrome 40 or later, you can open DevTools and then
reload your page. The Console tab will contain error messages with the correct
sha256 hash for each of your inline scripts.&lt;/p&gt;
&lt;h2 id=&quot;eval-too&quot;&gt;Eval too &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#eval-too&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Even when an attacker can&#39;t inject script directly, they might be able to trick
your application into converting otherwise inert text into executable JavaScript
and executing it on their behalf. &lt;code&gt;eval()&lt;/code&gt;, &lt;code&gt;new Function()&lt;/code&gt;, &lt;code&gt;setTimeout([string], …)&lt;/code&gt;, and
&lt;code&gt;setInterval([string], ...)&lt;/code&gt; are all vectors through which injected
text might end up executing something unexpectedly malicious. CSP&#39;s default
response to this risk is to completely block all of these vectors.&lt;/p&gt;
&lt;p&gt;This has more than a few impacts on the way you build applications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You must parse JSON via the built-in &lt;code&gt;JSON.parse&lt;/code&gt;, rather than relying on
&lt;code&gt;eval&lt;/code&gt;. Native JSON operations are available in
&lt;a href=&quot;https://caniuse.com/#feat=json&quot; rel=&quot;noopener&quot;&gt;every browser since IE8&lt;/a&gt;, and they&#39;re
completely safe.&lt;/li&gt;
&lt;li&gt;Rewrite any &lt;code&gt;setTimeout&lt;/code&gt; or &lt;code&gt;setInterval&lt;/code&gt; calls you&#39;re currently making
with inline functions rather than strings. For example:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;document.querySelector(&#39;a&#39;).style.display = &#39;none&#39;;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;would be better written as:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;setTimeout&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 punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;a&#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;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;display &lt;span class=&quot;token operator&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;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 number&quot;&gt;10&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Avoid inline templating at runtime: Many templating libraries use &lt;code&gt;new Function()&lt;/code&gt; liberally to speed up template generation at runtime. It&#39;s a
nifty application of dynamic programming, but comes at the risk of
evaluating malicious text. Some frameworks support CSP out of the box,
falling back to a robust parser in the absence of &lt;code&gt;eval&lt;/code&gt;.
&lt;a href=&quot;https://docs.angularjs.org/api/ng/directive/ngCsp&quot; rel=&quot;noopener&quot;&gt;AngularJS&#39;s ng-csp directive&lt;/a&gt;
is a good example of this.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, a better choice would be a templating language that offers
precompilation (&lt;a href=&quot;https://handlebarsjs.com/installation/precompilation.html&quot; rel=&quot;noopener&quot;&gt;Handlebars does&lt;/a&gt;,
for instance). Precompiling your templates can make the user experience even
faster than the fastest runtime implementation, and it&#39;s safer too.  If eval and
its text-to-JavaScript brethren are essential to your application, you can
enable them by adding &lt;code&gt;&#39;unsafe-eval&#39;&lt;/code&gt; as an allowed source in a &lt;code&gt;script-src&lt;/code&gt;
directive, but we strongly discourage this. Banning the ability to execute
strings makes it much more difficult for an attacker to execute unauthorized
code on your site.&lt;/p&gt;
&lt;h2 id=&quot;reporting&quot;&gt;Reporting &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#reporting&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CSP&#39;s ability to block untrusted resources client-side is a huge win for your
users, but it would be quite helpful to have some sort of notification
sent back to the server so that you can identify and squash any bugs that allow
malicious injection in the first place. To this end, you can instruct the
browser to &lt;code&gt;POST&lt;/code&gt; JSON-formatted violation reports to a location
specified in a &lt;code&gt;report-uri&lt;/code&gt; directive.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Security-Policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value csp languages-csp&quot;&gt;default-src &#39;self&#39;; ...; report-uri /my_amazing_csp_report_parser;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Those reports will look something like the following:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;csp-report&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;document-uri&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;http://example.org/page.html&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;referrer&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;http://evil.example.com/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;blocked-uri&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;http://evil.example.com/evil.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;violated-directive&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;script-src &#39;self&#39; https://apis.google.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;original-policy&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;script-src &#39;self&#39; https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser&quot;&lt;/span&gt;&lt;br /&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;p&gt;This contains a good chunk of information that will help you track down the
specific cause of the violation, including the page on which the violation
occurred (&lt;code&gt;document-uri&lt;/code&gt;), that page&#39;s referrer (note that unlike the HTTP
header field, the key is &lt;em&gt;not&lt;/em&gt; misspelled), the resource that violated the
page&#39;s policy (&lt;code&gt;blocked-uri&lt;/code&gt;), the specific directive it violated
(&lt;code&gt;violated-directive&lt;/code&gt;), and the page&#39;s complete policy (&lt;code&gt;original-policy&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;report-only&quot;&gt;Report-Only &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#report-only&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you&#39;re just starting out with CSP, it makes sense to evaluate the current
state of your application before rolling out a draconian policy to your users.
As a stepping stone to a complete deployment, you can ask the browser to monitor
a policy, reporting violations but not enforcing the restrictions. Instead of
sending a &lt;code&gt;Content-Security-Policy&lt;/code&gt; header, send a
&lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt; header.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Security-Policy-Report-Only&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;default-src &#39;self&#39;; ...; report-uri /my_amazing_csp_report_parser;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The policy specified in report-only mode won&#39;t block restricted resources, but
it will send violation reports to the location you specify. You can even send
&lt;em&gt;both&lt;/em&gt; headers, enforcing one policy while monitoring another. This is a great
way to evaluate the effect of changes to your application&#39;s CSP: turn on
reporting for a new policy, monitor the violation reports and fix any bugs that
turn up; when you&#39;re satisfied with its effect, start enforcing the new policy.&lt;/p&gt;
&lt;h2 id=&quot;real-world-usage&quot;&gt;Real World Usage &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#real-world-usage&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CSP 1 is quite usable in Chrome, Safari, and Firefox, but has very limited
support in IE 10. You can &lt;a href=&quot;https://caniuse.com/#feat=contentsecuritypolicy&quot; rel=&quot;noopener&quot;&gt;view specifics at caniuse.com&lt;/a&gt;. CSP Level 2 has been available in Chrome since
version 40. Massive sites like Twitter and Facebook have deployed the header
(&lt;a href=&quot;https://blog.twitter.com/engineering/en_us/a/2011/improving-browser-security-with-csp.html&quot; rel=&quot;noopener&quot;&gt;Twitter&#39;s
case study&lt;/a&gt; is worth a read), and the standard is very much ready
for you to start deploying on your own sites.&lt;/p&gt;
&lt;p&gt;The first step towards crafting a policy for your application is to evaluate the
resources you&#39;re actually loading. Once you think you have a handle on how
things are put together in your app, set up a policy based on those
requirements. Let&#39;s walk through a few common use cases and determine how we&#39;d
best be able to support them within the protective confines of CSP.&lt;/p&gt;
&lt;h3 id=&quot;use-case-#1-social-media-widgets&quot;&gt;Use case #1: social media widgets &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#use-case-#1-social-media-widgets&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Facebook&#39;s &lt;a href=&quot;https://developers.facebook.com/docs/plugins/like-button&quot; class=&quot;external&quot; rel=&quot;noopener&quot;&gt;Like button&lt;/a&gt;
has a number of implementation options. We recommend sticking with the
&lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; version as it&#39;s safely sandboxed from the rest of your site. It
requires a &lt;code&gt;child-src https://facebook.com&lt;/code&gt; directive to function properly. Note
that, by default, the &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; code that Facebook provides loads a relative
URL, &lt;code&gt;//facebook.com&lt;/code&gt;. Change that to explicitly specify HTTPS:
&lt;code&gt;https://facebook.com&lt;/code&gt;. There&#39;s no reason to use HTTP if you don&#39;t have to.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Twitter&#39;s &lt;a href=&quot;https://publish.twitter.com/#&quot; rel=&quot;noopener&quot;&gt;Tweet button&lt;/a&gt;
relies on access to a script and a frame, both hosted at
&lt;code&gt;https://platform.twitter.com&lt;/code&gt;. (Twitter likewise provides a relative URL by
default; edit the code to specify HTTPS when copy/pasting it locally.)
You&#39;ll be all set with &lt;code&gt;script-src https://platform.twitter.com; child-src https://platform.twitter.com&lt;/code&gt;, as long as you move the JavaScript snippet
that Twitter provides out into an external JavaScript file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Other platforms have similar requirements, and can be addressed similarly.
We suggest just setting a &lt;code&gt;default-src&lt;/code&gt; of &lt;code&gt;&#39;none&#39;&lt;/code&gt;, and watching your console to
determine which resources you&#39;ll need to enable to make the widgets work.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Including multiple widgets is straightforward: simply combine the policy
directives, remembering to merge all resources of a single type into a single
directive. If you wanted all three social media widgets, the policy would look
like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;use-case-#2-lockdown&quot;&gt;Use case #2: lockdown &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#use-case-#2-lockdown&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Assume for a moment that you run a banking site and want to make sure that
only those resources you&#39;ve written yourself can be loaded. In this scenario,
start with a default policy that blocks absolutely everything (&lt;code&gt;default-src &#39;none&#39;&lt;/code&gt;), and build up from there.&lt;/p&gt;
&lt;p&gt;Let&#39;s say the bank loads all images, style, and script from a CDN at
&lt;code&gt;https://cdn.mybank.net&lt;/code&gt;, and connects via XHR to &lt;code&gt;https://api.mybank.com/&lt;/code&gt; to
pull various bits of data down. Frames are used, but only for pages local to the
site (no third-party origins). There&#39;s no Flash on the site, no fonts, no
extras. The most restrictive CSP header that we could send is this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Security-Policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value csp languages-csp&quot;&gt;default-src &#39;none&#39;; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; child-src &#39;self&#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;use-case-#3-ssl-only&quot;&gt;Use case #3: SSL only &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#use-case-#3-ssl-only&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A wedding-ring discussion forum admin wants to ensure that all resources are
only loaded via secure channels, but doesn&#39;t really write much code; rewriting
large chunks of the third-party forum software that&#39;s filled to the brim with
inline script and style is beyond his abilities. The following policy would be
effective:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Security-Policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value csp languages-csp&quot;&gt;default-src https:; script-src https: &#39;unsafe-inline&#39;; style-src https: &#39;unsafe-inline&#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Even though &lt;code&gt;https:&lt;/code&gt; is specified in &lt;code&gt;default-src&lt;/code&gt;, the script and style
directives don&#39;t automatically inherit that source. Each directive completely
overwrites the default for that specific type of resource.&lt;/p&gt;
&lt;h2 id=&quot;the-future&quot;&gt;The future &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/csp/#the-future&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Content Security Policy Level 2 is a
&lt;a href=&quot;https://www.w3.org/TR/CSP2/&quot; rel=&quot;noopener&quot;&gt;Candidate Recommendation&lt;/a&gt;. The W3C&#39;s Web Application Security Working Group
has already begun work on the specification&#39;s next iteration,
&lt;a href=&quot;https://www.w3.org/TR/CSP3/&quot; rel=&quot;noopener&quot;&gt;Content Security Policy Level 3&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;re interested in the discussion around these upcoming features,
&lt;a href=&quot;http://lists.w3.org/Archives/Public/public-webappsec/&quot; rel=&quot;noopener&quot;&gt;skim the public-webappsec@ mailing list archives&lt;/a&gt;,
or join in yourself.&lt;/p&gt;
</content>
    <author>
      <name>Mike West</name>
    </author><author>
      <name>Joe Medley</name>
    </author>
  </entry>
</feed>
