This is the first in a series of blog posts about server headers
Heads up! We’re about to launch WASP, a Web Application Security Platform. The aim of WASP is to help you manage (well, you guessed it) the security of your Posit Connect application using Content Security Policy and Network Error Logging. More details soon, but if this interests you, please get in touch.
This blog post is aimed at those who are somewhat tech literate but not necessarily a security expert. We’re aiming to introduce the concept of Content Security Policy and teach some of the technical aspects.
What is Content Security Policy?
Content Security Policy (CSP) is
a framework of modern (ish) browsers, that allows a developer to protect
an application through the use of the
header. It’s used to give applications an extra layer of security -
safeguarding against attacks such as cross-site scripting. In this blog
we’re going to take you through some of the basics of Content Security
Policy and show you why it’s a necessity for modern applications.
How will Content Security Policy help me?
How does CSP link to R?
The technical basics
A Content Security Policy HTTP header is set on the server side, but
protects the client side. A CSP header is split into directives - each
directive enabling you to specify an allow list (in some cases, a deny
list) of valid sources for content that the browser can (or is not
allowed to) load. For instance, one of the more common directives,
script-src, allows us to specify valid sources for scripts. Any
scripts that are from a source not listed within this directive will be
blocked from executing in the browser. A basic CSP header using
script-src might be
Content-Security-Policy: script-src 'self'`
self, is telling the browser to allow scripts to be
loaded from our domain. As there are no others sourced listed with it,
we are telling the browser to only allow scripts to be loaded from
our domain. There are other metasources:
'self': Content from the same domain,
'none': Nobody can include this functionality. In the case above, this would mean we accept scripts from no sources.
- A nonce / hash: Accept code with a specific nonce / hash.
Of course, we can also specify specific URL / domains. For instance,
Content-Security-Policy: script-src 'self' https://posit.co/
would allow loading of scripts from our own domain, and Posit. Other common directives include
default-src: Default values for
font-src: Valid sources for fonts loaded using the
frame-src: Valid sources for embedded frame contents.
img-src: Valid origins from which images can be loaded.
navigate-to: Restricted URLs from which a document can initiate navigation.
style-src: Valid sources for stylesheets.
media-src: Valid sources for loading media using
For a full list, see the MDN Web Doc.
Reporting Content-Security-Policy violations
If an attacker had found any vulnerabilities on our site, then using the directives above we would be blocking a good bunch of potential attacks for users on modern browsers. However, users on browsers (mainly Internet Explorer) that still do not support the CSP directives you’ve chosen are still at threat. It’s important that we understand which CSP directives are being targeted on our site, to protect the vulnerable on old browsers.
Directives are split into two categories; blockers and reporters.
Blockers block input into the application (think
reporters deliver reports about the blocks. This allows us to understand
which of our CSP directives are being targeted.
The most important reporting directive is
report-to. However, it’s
report-uri, still plays a crucial role. In fact, all
browsers will fall back to
report-uri if it can’t find
We’ll go into more detail on the differences between the two in a later
blog, but for now we’ll look into
report-uri (it’s a tad simpler).
report-uri directive allows us specify the URL(s) to which our CSP
violation should be reported. These URLs are usually API endpoints,
which process the report JSON. The following HTTP header would POST any
violations to the
csp-reporting endpoint on our domain
Content-Security-Policy: script-src 'self'; report-uri /csp-reporting
Any reports sent to this endpoint will be
Content-Type: application/reports+json and contain four important
pieces of information (plus some others):
blocked-uri: URI of the blocked resource
document-uri: URI of the document in which the violation occurred
original-policy: The original Content Security Policy
violated-directive: The CSP directive that was violated
The format will look something like
"violated-directive": "script-src 'self'",
"original-policy": script-src 'self'; report-uri /csp-reporting",
This report indicates that on the page
something has tried to load the style file located at
badwebsite.com/css/style.css. However, because we have the
script-src directive set to
"self", only scripts from our own domain
may be sourced.
Whilst CSP is a great addition to the security toolbox, there are some “limitations”:
- It’s not a magic wand. It’s a control to cut down on your application’s exposure - it will not patch vulnerabilities. Think of it like a firewall - it’s a secondary control, a defence technique. Mostly in case the developers have missed something. If you’re having trouble with any security issues, feel free to get in touch with us for advice.
- It’s only useful for client-side attacks on your application. It does not help with server-side, database attacks or anything in between.
- OK, this last one isn’t really a limitation, more of a warning. It’s
not on by default. The
Content-Security-PolicyHTTP header has to be added manually with each policy individually specified.
If Content Security Policy or Shiny app security in general interests you or you want more news on WASP, our new Web Application Security Platform, then please email firstname.lastname@example.org and we can discuss how to set this up for your applications.