I just wanted to share a few tips regarding the Content Security Policy meta tag that we need to use in PhoneGap/Cordova apps. I’m not going to cover all the gory details — for that, there are plenty of great sites.
I’m just going to focus on a few specific use cases when it comes to the intersection of CSP and Cordova/PhoneGap, but there’s a couple things we need to mention first.
The CSP Meta Tag
CSP directives are specified by a meta
tag, like so:
<meta http-equiv="Content-Security-Policy"
contents="...">
CSP Directives
CSP controls what sources are permitted and what sources aren’t. Because there are many different types of assets our page might need, CSP also allows us to be very granular with respect to what types of assets can be loaded from which sources. There’s several directives available, like so:
directive | description |
---|---|
img-src |
Image sources (like PNG, JPG, SVG, etc.) |
media-src |
Video/audio sources |
script-src |
Script sources |
style-src |
Stylesheet sources |
font-src |
Webfont sources |
default-src |
Fallback for most directives |
This isn’t the entire list of available directives, so you’ll want to check out the links at the head of this article for all the possibilities, but this should give you a pretty good idea of the granularity of CSP.
Furthermore, it’s important to note that there is a hierarchy of sorts — if you don’t specify img-src
, but do specify default-src
, then default-src
is used instead. If you specify both, however, the values won’t inherit from default-src
.
CSP Sources
A source is either a URL or a special keyword. A URL can look like this:
http://www.example.com
– allow resources from this domain, including any pages on ithttp://*.example.com
– allow resources from this domain, including any subdomains.*://*.example.com
– allow resources from this domain, any subdomains, and any URL scheme*://*.example.com:*
– allow resources from this domain, any subdomains, any URL scheme, and any port.
NOTE: Although it might appear that you can use wildcards anywhere, you can’t. You can only use a wildcard for the URL scheme, the left part of the domain, and the port.
There are four keywords that you can also use:
'none'
– indicates that no source is permitted. This disables access for the specified directive.'self'
– indicates that local resources are permitted.'unsafe-inline'
– permits inline scripts/styles'unsave-eval'
– permitseval()
and its ilk.
CSP Syntax
Each directive can have any number of sources. Each one is separated by a space. The entire set of directives are separated by semicolons. This makes things a little difficult to read, but that’s the way it’s built. For example, here’s a sample CSP tag:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self' https://*.example.com;
img-src 'self' https://images.example.com data:;
script-src 'self' https://scripts.example.com">
This isn’t a terribly useful CSP, but it does illustrate the syntax.
Common Cordova Uses
With all that out of the way, here’s some common tasks you might need to perform in a Cordova app — along with the directives you need to specify to permit them:
task | directive | value |
---|---|---|
iOS Support | default-src |
gap://* (1) |
Allow web socket communication | default-src |
ws://* (2) |
Execute / load local resources | default-src |
'self' (3) |
Load data: images |
img-src |
data: |
Permit eval() |
script-src |
'unsafe-eval' (4) |
Permit inline scripting | script-src |
'unsafe-inline' (5) |
Permit inline styles | style-src |
'unsafe-inline' |
Notes:
- This is critically important for your Cordova/PhoneGap apps running on iOS. Without it, plugins and Cordova events won’t work.
- If you use web sockets for communication, you’ll need to allow this URL scheme. Our example allows communication with any host on any port, but ideally you’ll be more specific.
- You should always have
'self'
in any directive so that you can load local resources. If you override any other directive, you’ll need to specify'self'
there too. - Only allow
eval()
if you absolutely must do so. Some plugins, libraries and frameworks will require it, but if you can avoid it, this should be avoided, as it can be a huge security hole. - Only allow inline scripting if you absolutely must. Again, some frameworks and such might require it, but it’s a huge security risk if you’re injecting dynamic HTML using untrusted data.
What about BrowserSync?
I really, really, really like to use BrowserSync when rapidly iterating, especially because it lets me have the same content loaded across multiple devices, including the desktop. When I make changes, the content can automatically be updated.
In order to use BrowserSync, however, you need to enable certain CSP rules. These should only be enabled during development, unless you’re using another framework or plugin that requires them:
- Add
ws://*
to thedefault-src
directive — BrowserSync communicates over web sockets. - Add
'unsafe-inline'
to thescript-src
directive.
You can also use
phonegap serve
and the PhoneGap Developer app for a similar experience. However, I’ve only had limited luck in getting this to work well within my typical build setup (which has all sorts of stuff going on!), while BrowserSync works a peach.