As a full-stack dev, I try my best to keep up on front and back end technologies,
methods, and techniques. One of the many ways I do this is by utilizing my time
through reading, watching, and listening. I have, at any time, 3-5 books I’m reading,
a slew of videos on my watch list, and a myriad of podcasts that I listen to which
help me stay aware of the numerous things that are relevant to me as a web dev.
One of the podcasts I listen to is Shop Talk Show. Aside from the various tips,
tricks, and information that I’ve absorbed from the podcast, I’ve also learned
how to talk about what I do through Chris and Dave. They constantly get
interesting questions and go down rabbit holes. In the http://shoptalkshow.com/episodes/237-rapidfire-73/” target=’_blank’>Last episode (#273), they get
into Content Security Policies. It’s something that I don’t hear people talk about
often and though it’s something I’ve always used and been aware of, I don’t think
I’ve ever written or posted about it. So I wanted to offer up a blog post.
The goal of a Content Security Policy (CSP) is to prevent Cross-Site Scripting
(XSS). There are a lot of ways it does this, which we’ll get into. How it works
is by directing the browser to enforce the policies set forth through HTTP directives.
The CSP sets a whitelist of content sources which the browser understands will be
the endpoint of requests made from the page. The browser uses this whitelist to
block requests made to content sources outside of the whitelist. Keep in mind that
CSP is not meant to be the only defense against XSS, just another tool in the
box. You should utilize other tools (like input sanitization) in addition to a
CSP to prevent XSS.
How It works
When a browser makes a request to your website, the CSP should be provided with
the HTML as an
http-header. It’s part of the header because it’s hard to forge.
The policy itself is a set of directives which instructs the browser to only
render or execute content from the whitelisted sources.
What A CSP Contains
source directives, or, a list of sources for specific content types.
Here’s the list of those:
default-src: the default source of all content types. This is used when a source
type is not defined. When a more specific source type is defined, it overrides the
base-uri: sets the URLs that can appear in the
child-src: sets the URLs for workers and embedded frame contents. For example:
child-src https://youtube.comwould allow embedding videos from YouTube but
not from other origins. This should be used instead of the deprecated
connect-src: sets the endpoints to which the page can connect via XHR, WebSockets,
font-src: sets the origins that can serve fonts.
form-action: sets the endpoints for
frame-ancestors: sets the sources that can embed the current page. This applies
<applet>tags. It can’t be used in
<meta>tags and applies only to non-HTML resources.
img-src: sets the origins from which images can be loaded.
media-src: sets the origins from which video and audio can be loaded.
object-src: sets control over Flash and other plug-ins.
plugin-types: sets the types of plug-ins pages may invoke.
report-uri: specifies a URL where a browser will send reports when a security
policy is violated. This can’t be used in
style-src: sets the origins from which stylesheets can be loaded.
script-src: sets the origins from which scripts can be loaded.
upgrade-insecure-requests: instructs browsers to rewrite URL schemes, changing
HTTP to HTTPS. This is for websites with large amounts of old URLS that need to
Why It’s Needed
By default, directives are open, meaning that all sources and endpoints are
allowed. It’s important to restrict the sources and endpoints because attackers
can use unknown sources to perform XSS.
How To Implement
To specify sources, there are a few valid values:
*: All origins/endpoints are valid
data: URIsto be used as a content source. This is insecure.
An attacker can inject arbitrary
data:URIs. This should be used sparingly and definitely not
http://example.com: All domains of
schemas are valid.
https://example.com: All domains of
example.comusing ONLY the
schema are valid.
http://*.example.com: All subdomains of
https://schema are valid.
https://*.exmple.com: All subdomains of
example.comusing ONLY the
schema are valid.
mail.example.com:433: All attempts to access port 433 on mail.example.com are valid.
Keywords are also used. When using keywords, single quotes are required.
'none': An empty set. No URLs are allowed.
'self': The origin from which the originating document is served, including the
same URL scheme and port number.
'unsafe-inline': Allows the use of inline resources (i.e.
'unsafe-eval': Allows the use of
eval()and similar methods for creating
code from strings.
Notes on the Above:
http:// can redirect to
https:// will not redirect to
If a port number isn’t specified, the default port will be used. If no schema is
specified, the same on used to access the originating document is assumed. Allowing
a domain does not include it’s subdomains, but does allow extensions (i.e.
https://example.com/test to be used but not
Setting the CSP HTTP Header
The CSP’s best delivery method is through HTTP headers. Here are some examples how:
Header set Content-Security-Policy "default-src 'self';" # IIS Web.config <system.webServer> <httpProtocol> <customHeaders> <add name="Content-Security-Policy" value="default-src 'self;'" /> </customHeaders> </httpProtocol> </system.webServer>
# nginx conf file add_header Content-Security-Policy "default-src 'self';"
A lot of languages and frameworks support adding the headers programmatically, such
as PHP or Node.js.
header("Content-Security-Policy", "default-src 'self'");
# node-js request.setHeader("Content-Security-Policy", "default-src 'self'");
There is also an HTML5
<meta name='Content-Security-Policy' content="default-src 'self'; script-src https://google.com 'self'; ...; ...;" />
This tag goes in the
<head> of the page.
When setting directives, you should always include multiple URLs in one directive
(if multiple URLs are necessary). For example, if you want to allow images from
images.google.com, setting it across two directives would render
whichever came first useless because the latter would override the former.
img-src https://fbcdn.com; img-src https://images.google.com;
The second directive overrides the first directive.
Instead, multiple URLs should be declared in one directive, i.e.
img-src https://fbcdn.com https://images.google.com;
Specific directories are not allowed, i.e.
https://fbcdn.com/images. If you want
to use a specific directory, just use the web root (i.e.
I use a lot of resources to write my articles and make sure everything is up to snuff.
Here are some great articles/documentation:
Level 2 Spec on W3C
Mozilla Dev Article
We reviewed Content Security Policies, what they are, why they’re needed, what
they do, how to implement them, and the syntax.