Skip to content

Commit

Permalink
Separate browser policy functions into two packages.
Browse files Browse the repository at this point in the history
* browser-policy uses browser-policy-framing and browser-policy-content, both of
  which set default policies when they are used. This way you get a default
  policy when you add a browser policy package, but you can pick and choose
  different packages if you only want to think about one of them.
* The two packages use different namespaces: BrowserPolicy.framing and
  BrowserPolicy.content, which meant some functions got renamed (e.g. not using
  "framing" or "content in the function name when it's already in the
  namespace).
  • Loading branch information
Emily Stark committed Oct 3, 2013
1 parent d5159ae commit b5286b9
Show file tree
Hide file tree
Showing 14 changed files with 452 additions and 399 deletions.
124 changes: 67 additions & 57 deletions docs/client/packages/browser-policy.html
Expand Up @@ -6,49 +6,53 @@
enforced by newer browsers. These policies help you prevent and mitigate common
attacks like cross-site scripting and clickjacking.

`browser-policy` lets you configure the HTTP headers X-Frame-Options and
Content-Security-Policy. X-Frame-Options tells the browser which websites are
allowed to frame your app. You should only let trusted websites frame your app,
because malicious sites could harm your users
with <a href="https://www.owasp.org/index.php/Clickjacking">clickjacking
When you add `browser-policy` to your app, you get default configurations for
the HTTP headers X-Frame-Options and Content-Security-Policy. X-Frame-Options
tells the browser which websites are allowed to frame your app. You should only
let trusted websites frame your app, because malicious sites could harm your
users with <a href="https://www.owasp.org/index.php/Clickjacking">clickjacking
attacks</a>.
<a href="https://developer.mozilla.org/en-US/docs/Security/CSP/Introducing_Content_Security_Policy">Content-Security-Policy</a>
tells the browser where your app can load content from, which encourages safe
practices and mitigates the damage of a cross-site-scripting attack.
`browser-policy` also provides functions for you to configure these policies if
the defaults are not suitable.

For most apps, we recommend that you take the following steps when using
`browser-policy`:

* Call `BrowserPolicy.enableContentSecurityPolicy()` to enable a starter policy
for your app. With this starter policy, your app's client code will be able to
load content (images, scripts, fonts, etc.) only from its own origin, except
that XMLHttpRequests and WebSocket connections can go to any origin. Further,
your app's client code will not be able to use functions such as `eval()` that
convert strings to code.
* You can use the functions described below to customize the content
security policy. If your app does not need any inline Javascript such as inline
`<script>` tags, we recommend that you modify the policy by calling
`BrowserPolicy.disallowInlineScripts()` in server code. This will result in one
extra round trip when your app is loaded, but will help prevent cross-site
scripting attacks by disabling all scripts except those loaded from a `script
src` attribute.
* If your app does not need to be framed by other websites, call
`BrowserPolicy.allowFramingBySameOrigin()` to help prevent clickjacking attacks.
If you only want to use Content-Security-Policy or X-Frame-Options but not both,
you can add the individual packages `browser-policy-content` or
`browser-policy-framing` instead of `browser-policy`.

For most apps, we recommend that you take the following steps:

* Add `browser-policy` to your app to enable a starter policy. With this starter
policy, your app's client code will be able to load content (images, scripts,
fonts, etc.) only from its own origin, except that XMLHttpRequests and WebSocket
connections can go to any origin. Further, your app's client code will not be
able to use functions such as `eval()` that convert strings to code. Users'
browsers will only let your app be framed by web pages on the same origin as
your app.
* You can use the functions described below to customize the policies. If your
app does not need any inline Javascript such as inline `<script>` tags, we
recommend that you modify the policy by calling
`BrowserPolicy.content.disallowInlineScripts()` in server code. This will result
in one extra round trip when your app is loaded, but will help prevent
cross-site scripting attacks by disabling all scripts except those loaded from a
`script src` attribute.

Meteor determines the browser policy when the server starts up, so you should
call `BrowserPolicy` functions in top-level application code or in
`Meteor.startup`.

#### Frame options

You can use the following functions to specify which websites are allowed to
frame your app. By default, any website is allowed.
By default, only web pages on the same origin as your app are allowed to frame
your app. You can use the following functions to modify this policy.
<dl class="callbacks">
{{#dtdd "BrowserPolicy.disallowFraming()"}}
{{#dtdd "BrowserPolicy.framing.disallow()"}}
Your app will never render inside a frame or iframe.
{{/dtdd}}

{{#dtdd "BrowserPolicy.restrictFramingToOrigin(origin)"}}
{{#dtdd "BrowserPolicy.framing.restrictToOrigin(origin)"}}
Your app will only render inside frames loaded by `origin`. You can only call
this function once with a single origin, and cannot use wildcards or specify
multiple origins that are allowed to frame your app. (This is a limitation of
Expand All @@ -60,47 +64,46 @@
{{/warning}}
{{/dtdd}}

{{#dtdd "BrowserPolicy.restrictFramingToSameOrigin()"}}
Your app will only render inside frames loaded by webpages on the same origin as
your app.
{{#dtdd "BrowserPolicy.framing.allowAll()"}}
This unsets the X-Frame-Options header, so that your app can be framed by
any webpage.
{{/dtdd}}
</dl>

#### Content options

You can use the functions in this section to control how different types of
content can be loaded on your site. In order to use any of these functions, you
must first call `BrowserPolicy.enableContentSecurityPolicy()`, which enables the
starter policy described above. This section covers additional functions that
you can use to tighten or relax restrictions on what content your app can use.
content can be loaded on your site.

You can use the following functions to adjust policies on where Javascript and
CSS can be run:

<dl class="callbacks">
{{#dtdd "BrowserPolicy.allowInlineScripts()"}}
{{#dtdd "BrowserPolicy.content.allowInlineScripts()"}}
Allows inline `<script>` tags, `javascript:` URLs, and inline event handlers.
The default policy already allows inline scripts.
{{/dtdd}}

{{#dtdd "BrowserPolicy.disallowInlineScripts()"}}
{{#dtdd "BrowserPolicy.content.disallowInlineScripts()"}}
Disallows inline Javascript. Calling this function results in an extra
round-trip on page load to retrieve Meteor runtime configuration that is usually
part of an inline script tag.
{{/dtdd}}

{{#dtdd "BrowserPolicy.allowEval()"}}
{{#dtdd "BrowserPolicy.content.allowEval()"}}
Allows the creation of Javascript code from strings using function such as `eval()`.
{{/dtdd}}

{{#dtdd "BrowserPolicy.disallowEval()"}}
Disallows eval and related functions.
{{#dtdd "BrowserPolicy.content.disallowEval()"}}
Disallows eval and related functions. The default policy already disallows eval.
{{/dtdd}}

{{#dtdd "BrowserPolicy.allowInlineStyles()"}}
Allows inline style tags and style attributes.
{{#dtdd "BrowserPolicy.content.allowInlineStyles()"}}
Allows inline style tags and style attributes. The default policy already allows
inline styles.
{{/dtdd}}

{{#dtdd "BrowserPolicy.disallowInlineStyles()"}}
{{#dtdd "BrowserPolicy.content.disallowInlineStyles()"}}
Disallows inline CSS.
{{/dtdd}}
</dl>
Expand All @@ -110,7 +113,7 @@
script, object, image, media, font, and connect.

<dl class="callbacks">
{{#dtdd "BrowserPolicy.allow&lt;ContentType&gt;Origin(origin)"}}
{{#dtdd "BrowserPolicy.content.allow&lt;ContentType&gt;Origin(origin)"}}
Allows this type of content to be loaded from the given origin. `origin` is a
string and can include an optional scheme (such as `http` or `https`), an
optional wildcard at the beginning, and an optional port which can be a
Expand All @@ -119,34 +122,41 @@
origins to specify a whitelist of allowed origins.
{{/dtdd}}

{{#dtdd "BrowserPolicy.allow&lt;ContentType&gt;DataUrl()"}}
{{#dtdd "BrowserPolicy.content.allow&lt;ContentType&gt;DataUrl()"}}
Allows this type of content to be loaded from a `data:` URL.
{{/dtdd}}

{{#dtdd "BrowserPolicy.allow&lt;ContentType&gt;SameOrigin()"}}
{{#dtdd "BrowserPolicy.content.allow&lt;ContentType&gt;SameOrigin()"}}
Allows this type of content to be loaded from the same origin as your app.
{{/dtdd}}

{{#dtdd "BrowserPolicy.disallow&lt;ContentType&gt;()"}}
{{#dtdd "BrowserPolicy.content.disallow&lt;ContentType&gt;()"}}
Disallows this type of content on your app.
{{/dtdd}}
</dl>

These functions are also defined for the content type `AllContent`, which is a
shorthand for calling one of the above functions once for each content type.
For example, if you want to allow the origin `https://foo.com` for all types of
content but you want to disable `<object>` tags, you can call
`BrowserPolicy.allowAllContentOrigin("https://foo.com")` followed by
`BrowserPolicy.disallowObject()`.
You can also set policies for all these types of content at once, using these
functions:

* `BrowserPolicy.content.allowSameOriginForAll()`,
* `BrowserPolicy.content.allowDataUrlForAll()`,
* `BrowserPolicy.content.allowOriginForAll(origin)`
* `BrowserPolicy.content.disallowAll()`

For example, if you want to allow the
origin `https://foo.com` for all types of content but you want to disable
`<object>` tags, you can call
`BrowserPolicy.content.allowOriginForAll("https://foo.com")` followed by
`BrowserPolicy.content.disallowObject()`.

Other examples of using the `BrowserPolicy` API:
Other examples of using the `BrowserPolicy.content` API:

* `BrowserPolicy.disallowObject()` causes the browser to disallow all
`<object>` tags.
* `BrowserPolicy.allowImageOrigin("https://example.com")`
* `BrowserPolicy.content.disallowFont()` causes the browser to disallow all
`<font>` tags.
* `BrowserPolicy.content.allowImageOrigin("https://example.com")`
allows images to have their `src` attributes point to images served from
`https://example.com`.
* `BrowserPolicy.allowConnectOrigin("https://example.com")` allows XMLHttpRequest
* `BrowserPolicy.content.allowConnectOrigin("https://example.com")` allows XMLHttpRequest
and WebSocket connections to `https://example.com`.


Expand Down
1 change: 1 addition & 0 deletions packages/browser-policy-common/.gitignore
@@ -0,0 +1 @@
.build*
27 changes: 27 additions & 0 deletions packages/browser-policy-common/browser-policy-common.js
@@ -0,0 +1,27 @@
BrowserPolicy = {};

var inTest = false;

BrowserPolicy._runningTest = function () {
return inTest;
};

BrowserPolicy._setRunningTest = function () {
inTest = true;
};

WebApp.connectHandlers.use(function (req, res, next) {
// Never set headers inside tests because they could break other tests.
if (BrowserPolicy._runningTest())
return next();

var xFrameOptions = BrowserPolicy.framing &&
BrowserPolicy.framing._constructXFrameOptions();
var csp = BrowserPolicy.content &&
BrowserPolicy.content._constructCsp();
if (xFrameOptions)
res.setHeader("X-Frame-Options", xFrameOptions);
if (csp)
res.setHeader("Content-Security-Policy", csp);
next();
});
10 changes: 10 additions & 0 deletions packages/browser-policy-common/package.js
@@ -0,0 +1,10 @@
Package.describe({
summary: "Common code for browser-policy packages",
internal: true
});

Package.on_use(function (api) {
api.use('webapp', 'server');
api.add_files('browser-policy-common.js', 'server');
api.export('BrowserPolicy', 'server');
});
1 change: 1 addition & 0 deletions packages/browser-policy-content/.gitignore
@@ -0,0 +1 @@
.build*

0 comments on commit b5286b9

Please sign in to comment.