Set X-Content-Type-Options in browser-policy-content

This commit is contained in:
Emily Stark
2014-05-05 22:22:45 -07:00
parent 4afa54ca5a
commit a8673d01cd
4 changed files with 50 additions and 3 deletions

View File

@@ -169,6 +169,12 @@ sites can frame your site, while
`BrowserPolicy.content.allowFrameOrigin` allows you to control which
sites can be loaded inside frames on your site.
Adding `browser-policy-content` to your app also tells certain
browsers to avoid sniffing content types away from the declared type
(for example, interpreting a text file as JavaScript), using the
[X-Content-Type-Options](http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx)
header. To re-enable content sniffing, you can call
`BrowserPolicy.content.allowContentTypeSniffing()`.
{{/markdown}}
</template>

View File

@@ -19,9 +19,29 @@ WebApp.connectHandlers.use(function (req, res, next) {
BrowserPolicy.framing._constructXFrameOptions();
var csp = BrowserPolicy.content &&
BrowserPolicy.content._constructCsp();
if (xFrameOptions)
if (xFrameOptions) {
res.setHeader("X-Frame-Options", xFrameOptions);
if (csp)
}
if (csp) {
res.setHeader("Content-Security-Policy", csp);
}
next();
});
// We use `rawConnectHandlers` to set X-Content-Type-Options on all
// requests, including static files.
// XXX We should probably use `rawConnectHandlers` for X-Frame-Options
// and Content-Security-Policy too, but let's make sure that doesn't
// break anything first (e.g. the OAuth popup flow won't work well with
// a CSP that disallows inline scripts).
WebApp.rawConnectHandlers.use(function (req, res, next) {
if (BrowserPolicy._runningTest())
return next();
var contentTypeOptions = BrowserPolicy.content &&
BrowserPolicy.content._xContentTypeOptions();
if (contentTypeOptions) {
res.setHeader("X-Content-Type-Options", contentTypeOptions);
}
next();
});

View File

@@ -1,7 +1,8 @@
// By adding this package, you get the following default policy:
// No eval or other string-to-code, and content can only be loaded from the
// same origin as the app (except for XHRs and websocket connections, which can
// go to any origin).
// go to any origin). Browsers will also be told not to sniff content types
// away from declared content types (X-Content-Type-Options: nosniff).
//
// Apps should call BrowserPolicy.content.disallowInlineScripts() if they are
// not using any inline script tags and are willing to accept an extra round
@@ -32,6 +33,8 @@
// allowAllContentSameOrigin()
// disallowAllContent()
//
// You can allow content type sniffing by calling
// `BrowserPolicy.content.allowContentTypeSniffing()`.
var cspSrcs;
var cachedCsp; // Avoid constructing the header out of cspSrcs when possible.
@@ -44,6 +47,9 @@ var keywords = {
none: "'none'"
};
// If false, we set the X-Content-Type-Options header to 'nosniff'.
var contentSniffingAllowed = false;
BrowserPolicy.content = {};
var parseCsp = function (csp) {
@@ -134,6 +140,9 @@ var setWebAppInlineScripts = function (value) {
};
_.extend(BrowserPolicy.content, {
allowContentTypeSniffing: function () {
contentSniffingAllowed = true;
},
// Exported for tests and browser-policy-common.
_constructCsp: function () {
if (! cspSrcs || _.isEmpty(cspSrcs))
@@ -220,6 +229,12 @@ _.extend(BrowserPolicy.content, {
"default-src": []
};
setWebAppInlineScripts(false);
},
_xContentTypeOptions: function () {
if (! contentSniffingAllowed) {
return "nosniff";
}
}
});

View File

@@ -151,3 +151,9 @@ Tinytest.add("browser-policy - x-frame-options", function (test) {
BrowserPolicy.framing.restrictToOrigin("bar.com");
});
});
Tinytest.add("browser-policy - X-Content-Type-Options", function (test) {
test.equal(BrowserPolicy.content._xContentTypeOptions(), "nosniff");
BrowserPolicy.content.allowContentTypeSniffing();
test.equal(BrowserPolicy.content._xContentTypeOptions(), undefined);
});