Getting Started
Description
ContentSecurityPolicy makes working with the "Content-Security-Policy"
response header simple.
The "Content-Security-Policy" header is a header that restricts how a browser
can receive resources such as images and scripts. It's intent is to improve
security by making it more difficult for an attacker to get the browser to run
an arbitrary thing.
Installation
The package can be installed by adding content_security_policy to your list
of dependencies in mix.exs:
def deps do
[
{:content_security_policy, "~> 1.0"}
]
end
Why use this?
Using a "Content-Security-Policy" header is a great way to improve the
security of a web application that serves HTML to a browser. It allows the
specification of exactly which resources are allowed to be loaded and how.
The "Content-Security-Policy" header can specify, for example, that only
scripts from either the application's server or google.com which are retrieved
using https should be allowed. If an attacker were somehow able to inject a
script and get it to run, the browser would consult the
"Content-Security-Policy" header and then deny that script from running. This
makes it much harder for Cross-Site Scripting (XSS) attacks to succeed.
If you've used sobelow, with a
default Phoenix project, you may have noticed a warning telling you something
about a Content Security Policy. This project aims to make it extremely easy to
deal with that warning.
Another strength of this project is that it makes dealing with Content Security
Policy nonces simple. Nonces are a way of telling the browser that a specific
resource is okay when the server might otherwise not know how to describe that
resource via CSP. A good example of this is a dynamically generated QR Code.
Although it's possible to calculate the SHA hash of the QR code, it's often
easier to use a nonce and call it a day. For more on this use case check out
the documentation in the ContentSecurityPolicy.Plug.AddNonce plug.
Content Security Policy Terminology
There are many functions and modules which reference terminology of Content Security Policies. It's probably a good idea to define this terminology, so here goes.
Let's take an example content security policy header:
content-security-policy: default-src https: 'self'; img-src https://imgur.com;
That whole thing is known as the Content Security Policy Response Header.
The contents of that (default-src https: 'self'; img-src https://imgur.com;)
are referred to as the Content Security Policy or simply Policy.
That policy contains two Directives (default-src and img-src).
Each Directive contains a number of Source Values. The default-src
directive contains the https: and 'self' source values. The img-src
directive contains the https://imgur.com source value.
How does it work?
If we just want to set one Content Security Policy we can just add the following plug to our Router (in the appropriate pipeline or place, of course).
plug ContentSecurityPolicy.Plug.Setup(
default_policy: %ContentSecurityPolicy.Policy{
default_src: ["https:", "'self'"],
img_src: ["https://imgur.com"]
}
)
The above plug sets the content security policy struct to whatever is passed
in. This is assigned to conn.private.content_security_policy.
It also sets up a before_send action which serializes that value to a string
that the browser understands and stuffs it into the "content-security-policy"
header right before the response is sent. This means we can modify the content
security policy in conn.private.content_security_policy all we want and it'll
only ever be serialized once.
Adding a Source Value to a Directive
If a specific page has a resource that other pages do not, it is possible to add that specific source value to a directive for that controller function only. This means that you can get a bit more granular than simply setting a global content security policy that references resources that are only retrieved in very specific isntances.
For more on this see the ContentSecurityPolicy.Plug.AddSourceValue module
documentation.
Nonces
The ContentSecurityPolicy.Plug.AddNonce plug makes working with nonces easy.
For more on this functionality, check out the module documentation in
ContentSecurityPolicy.Plug.AddNonce.
Accessing Lower Level Functionality
The ContentSecurityPolicy module contains all of the functions you might need
if you want to interact with Content Security Policies at a lower level. The
plugs provided with this project should make this unnecessary... but if you
need this, it's there!