зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1089255 - Implement and test manifest-src CSP directive. r=bholley, r=dveditz, r=ckerschb
--- dom/base/nsContentPolicyUtils.h | 1 + dom/base/nsDataDocumentContentPolicy.cpp | 3 +- dom/base/nsIContentPolicy.idl | 2 +- dom/base/nsIContentPolicyBase.idl | 7 +- dom/base/nsISimpleContentPolicy.idl | 2 +- dom/base/test/csp/browser.ini | 4 + dom/base/test/csp/browser_test_web_manifest.js | 265 +++++++++++++++++++++ .../csp/browser_test_web_manifest_mixed_content.js | 55 +++++ dom/base/test/csp/file_CSP_web_manifest.html | 6 + dom/base/test/csp/file_CSP_web_manifest.json | 1 + .../test/csp/file_CSP_web_manifest.json^headers^ | 1 + dom/base/test/csp/file_CSP_web_manifest_https.html | 4 + dom/base/test/csp/file_CSP_web_manifest_https.json | 1 + .../csp/file_CSP_web_manifest_mixed_content.html | 9 + .../test/csp/file_CSP_web_manifest_remote.html | 8 + dom/base/test/csp/file_csp_testserver.sjs | 14 +- dom/base/test/csp/mochitest.ini | 7 + dom/base/test/moz.build | 5 +- dom/fetch/InternalRequest.cpp | 3 + dom/fetch/InternalRequest.h | 2 +- .../security/nsIContentSecurityPolicy.idl | 3 +- dom/ipc/manifestMessages.js | 25 +- dom/security/nsCSPUtils.cpp | 7 + dom/security/nsCSPUtils.h | 10 +- dom/security/nsMixedContentBlocker.cpp | 1 + dom/webidl/CSPDictionaries.webidl | 1 + extensions/permissions/nsContentBlocker.cpp | 6 +- netwerk/mime/nsMimeTypes.h | 1 + 28 files changed, 439 insertions(+), 15 deletions(-) create mode 100644 dom/base/test/csp/browser.ini create mode 100644 dom/base/test/csp/browser_test_web_manifest.js create mode 100644 dom/base/test/csp/browser_test_web_manifest_mixed_content.js create mode 100644 dom/base/test/csp/file_CSP_web_manifest.html create mode 100644 dom/base/test/csp/file_CSP_web_manifest.json create mode 100644 dom/base/test/csp/file_CSP_web_manifest.json^headers^ create mode 100644 dom/base/test/csp/file_CSP_web_manifest_https.html create mode 100644 dom/base/test/csp/file_CSP_web_manifest_https.json create mode 100644 dom/base/test/csp/file_CSP_web_manifest_mixed_content.html create mode 100644 dom/base/test/csp/file_CSP_web_manifest_remote.html
This commit is contained in:
Родитель
2cb38dd9d9
Коммит
8fc79cb285
|
@ -113,6 +113,7 @@ NS_CP_ContentTypeName(uint32_t contentType)
|
|||
CASE_RETURN( TYPE_BEACON );
|
||||
CASE_RETURN( TYPE_FETCH );
|
||||
CASE_RETURN( TYPE_IMAGESET );
|
||||
CASE_RETURN( TYPE_WEB_MANIFEST );
|
||||
default:
|
||||
return "<Unknown Type>";
|
||||
}
|
||||
|
|
|
@ -123,7 +123,8 @@ nsDataDocumentContentPolicy::ShouldLoad(uint32_t aContentType,
|
|||
aContentType == nsIContentPolicy::TYPE_SUBDOCUMENT ||
|
||||
aContentType == nsIContentPolicy::TYPE_SCRIPT ||
|
||||
aContentType == nsIContentPolicy::TYPE_XSLT ||
|
||||
aContentType == nsIContentPolicy::TYPE_FETCH) {
|
||||
aContentType == nsIContentPolicy::TYPE_FETCH ||
|
||||
aContentType == nsIContentPolicy::TYPE_WEB_MANIFEST) {
|
||||
*aDecision = nsIContentPolicy::REJECT_TYPE;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ interface nsIPrincipal;
|
|||
* by launching a dialog to prompt the user for something).
|
||||
*/
|
||||
|
||||
[scriptable,uuid(447a2300-ab3c-11e4-bcd8-0800200c9a66)]
|
||||
[scriptable,uuid(cb978019-0c5b-4067-abb6-c914461208c1)]
|
||||
interface nsIContentPolicy : nsIContentPolicyBase
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -24,7 +24,7 @@ typedef unsigned long nsContentPolicyType;
|
|||
* by launching a dialog to prompt the user for something).
|
||||
*/
|
||||
|
||||
[scriptable,uuid(21bb54b0-ab3c-11e4-bcd8-0800200c9a66)]
|
||||
[scriptable,uuid(4f2655e8-6365-4583-8510-732bff2186c5)]
|
||||
interface nsIContentPolicyBase : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -172,6 +172,11 @@ interface nsIContentPolicyBase : nsISupports
|
|||
*/
|
||||
const nsContentPolicyType TYPE_IMAGESET = 21;
|
||||
|
||||
/**
|
||||
* Indicates a web manifest.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_WEB_MANIFEST = 22;
|
||||
|
||||
/* When adding new content types, please update nsContentBlocker,
|
||||
* NS_CP_ContentTypeName, nsCSPContext, all nsIContentPolicy
|
||||
* implementations, and other things that are not listed here that are
|
||||
|
|
|
@ -28,7 +28,7 @@ interface nsIDOMElement;
|
|||
* by launching a dialog to prompt the user for something).
|
||||
*/
|
||||
|
||||
[scriptable,uuid(83d93c70-ab46-11e4-bcd8-0800200c9a66)]
|
||||
[scriptable,uuid(704b4b8e-2287-498a-9c0a-d1bde547a2d4)]
|
||||
interface nsISimpleContentPolicy : nsIContentPolicyBase
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Bug 1170385 - csp-on-violate-policy message not sent in browser tests with e10s
|
||||
[browser_test_web_manifest.js]
|
||||
[browser_test_web_manifest_mixed_content.js]
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Description of the tests:
|
||||
* These tests check for conformance to the CSP spec as they relate to Web Manifests.
|
||||
*
|
||||
* In particular, the tests check that default-src and manifest-src directives are
|
||||
* are respected by the ManifestObtainer.
|
||||
*/
|
||||
/*globals Components*/
|
||||
'use strict';
|
||||
requestLongerTimeout(10); // e10s tests take time.
|
||||
const {
|
||||
ManifestObtainer
|
||||
} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {});
|
||||
const path = '/tests/dom/base/test/csp/';
|
||||
const testFile = `file=${path}file_CSP_web_manifest.html`;
|
||||
const remoteFile = `file=${path}file_CSP_web_manifest_remote.html`;
|
||||
const httpsManifest = `file=${path}file_CSP_web_manifest_https.html`;
|
||||
const mixedContent = `file=${path}file_CSP_web_manifest_mixed_content.html`;
|
||||
const server = 'file_csp_testserver.sjs';
|
||||
const defaultURL = `http://example.org${path}${server}`;
|
||||
const remoteURL = `http://mochi.test:8888`;
|
||||
const secureURL = `https://example.com${path}${server}`;
|
||||
const tests = [
|
||||
// CSP block everything, so trying to load a manifest
|
||||
// will result in a policy violation.
|
||||
{
|
||||
expected: `default-src 'none' blocks fetching manifest.`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`csp=default-src 'none'`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(topic) {
|
||||
is(topic, 'csp-on-violate-policy', this.expected);
|
||||
}
|
||||
},
|
||||
// CSP allows fetching only from mochi.test:8888,
|
||||
// so trying to load a manifest from same origin
|
||||
// triggers a CSP violation.
|
||||
{
|
||||
expected: `default-src mochi.test:8888 blocks manifest fetching.`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`csp=default-src mochi.test:8888`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(topic) {
|
||||
is(topic, 'csp-on-violate-policy', this.expected);
|
||||
}
|
||||
},
|
||||
// CSP restricts fetching to 'self', so allowing the manifest
|
||||
// to load. The name of the manifest is then checked.
|
||||
{
|
||||
expected: `CSP default-src 'self' allows fetch of manifest.`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`csp=default-src 'self'`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(manifest) {
|
||||
is(manifest.name, 'loaded', this.expected);
|
||||
}
|
||||
},
|
||||
// CSP only allows fetching from mochi.test:8888 and remoteFile
|
||||
// requests a manifest from that origin, so manifest should load.
|
||||
{
|
||||
expected: 'CSP default-src mochi.test:8888 allows fetching manifest.',
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`csp=default-src http://mochi.test:8888`,
|
||||
remoteFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(manifest) {
|
||||
is(manifest.name, 'loaded', this.expected);
|
||||
}
|
||||
},
|
||||
// default-src blocks everything, so any attempt to
|
||||
// fetch a manifest from another origin will trigger a
|
||||
// policy violation.
|
||||
{
|
||||
expected: `default-src 'none' blocks mochi.test:8888`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`csp=default-src 'none'`,
|
||||
remoteFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(topic) {
|
||||
is(topic, 'csp-on-violate-policy', this.expected);
|
||||
}
|
||||
},
|
||||
// CSP allows fetching from self, so manifest should load.
|
||||
{
|
||||
expected: `CSP manifest-src allows self`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`manifest-src 'self'`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(manifest) {
|
||||
is(manifest.name, 'loaded', this.expected);
|
||||
}
|
||||
},
|
||||
// CSP allows fetching from example.org, so manifest should load.
|
||||
{
|
||||
expected: `CSP manifest-src allows http://example.org`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`manifest-src http://example.org`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(manifest) {
|
||||
is(manifest.name, 'loaded', this.expected);
|
||||
}
|
||||
},
|
||||
// Check interaction with default-src and another origin,
|
||||
// CSP allows fetching from example.org, so manifest should load.
|
||||
{
|
||||
expected: `CSP manifest-src overrides default-src of elsewhere.com`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`default-src: http://elsewhere.com; manifest-src http://example.org`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(manifest) {
|
||||
is(manifest.name, 'loaded', this.expected);
|
||||
}
|
||||
},
|
||||
// Check interaction with default-src none,
|
||||
// CSP allows fetching manifest from example.org, so manifest should load.
|
||||
{
|
||||
expected: `CSP manifest-src overrides default-src`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`default-src: 'none'; manifest-src 'self'`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(manifest) {
|
||||
is(manifest.name, 'loaded', this.expected);
|
||||
}
|
||||
},
|
||||
// CSP allows fetching from mochi.test:8888, which has a
|
||||
// CORS header set to '*'. So the manifest should load.
|
||||
{
|
||||
expected: `CSP manifest-src allows mochi.test:8888`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`csp=default-src *; manifest-src http://mochi.test:8888`,
|
||||
remoteFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(manifest) {
|
||||
is(manifest.name, 'loaded', this.expected);
|
||||
}
|
||||
},
|
||||
// CSP restricts fetching to mochi.test:8888, but the test
|
||||
// file is at example.org. Hence, a policy violation is
|
||||
// triggered.
|
||||
{
|
||||
expected: `CSP blocks manifest fetching from example.org.`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`csp=manifest-src mochi.test:8888`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(topic) {
|
||||
is(topic, 'csp-on-violate-policy', this.expected);
|
||||
}
|
||||
},
|
||||
// CSP is set to only allow manifest to be loaded from same origin,
|
||||
// but the remote file attempts to load from a different origin. Thus
|
||||
// this causes a CSP violation.
|
||||
{
|
||||
expected: `CSP manifest-src 'self' blocks cross-origin fetch.`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`csp=manifest-src 'self'`,
|
||||
remoteFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(topic) {
|
||||
is(topic, 'csp-on-violate-policy', this.expected);
|
||||
}
|
||||
}
|
||||
];
|
||||
//jscs:disable
|
||||
add_task(function* () {
|
||||
//jscs:enable
|
||||
for (let test of tests) {
|
||||
let tabOptions = {
|
||||
gBrowser: gBrowser,
|
||||
url: test.tabURL,
|
||||
};
|
||||
yield BrowserTestUtils.withNewTab(
|
||||
tabOptions,
|
||||
browser => testObtainingManifest(browser, test)
|
||||
);
|
||||
}
|
||||
|
||||
function* testObtainingManifest(aBrowser, aTest) {
|
||||
const observer = (/blocks/.test(aTest.expected)) ? new NetworkObserver(aTest) : null;
|
||||
const obtainer = new ManifestObtainer();
|
||||
let manifest;
|
||||
// Expect an exception (from promise rejection) if there a content policy
|
||||
// that is violated.
|
||||
try {
|
||||
manifest = yield obtainer.obtainManifest(aBrowser);
|
||||
} catch (e) {
|
||||
const msg = `Expected promise rejection obtaining.`;
|
||||
ok(/blocked the loading of a resource/.test(e.message), msg);
|
||||
if (observer) {
|
||||
yield observer.finished;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// otherwise, we test manifest's content.
|
||||
if (manifest) {
|
||||
aTest.run(manifest);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Helper object used to observe policy violations. It waits 10 seconds
|
||||
// for a response, and then times out causing its associated test to fail.
|
||||
function NetworkObserver(test) {
|
||||
let finishedTest;
|
||||
let success = false;
|
||||
this.finished = new Promise((resolver) => {
|
||||
finishedTest = resolver;
|
||||
})
|
||||
this.observe = function observer(subject, topic) {
|
||||
SpecialPowers.removeObserver(this, 'csp-on-violate-policy');
|
||||
test.run(topic);
|
||||
finishedTest();
|
||||
success = true;
|
||||
};
|
||||
SpecialPowers.addObserver(this, 'csp-on-violate-policy', false);
|
||||
setTimeout(() => {
|
||||
if (!success) {
|
||||
test.run('This test timed out.');
|
||||
finishedTest();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* Check that mixed content blocker works prevents fetches of
|
||||
* mixed content manifests.
|
||||
*/
|
||||
'use strict';
|
||||
const {
|
||||
ManifestObtainer
|
||||
} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {});
|
||||
const path = '/tests/dom/base/test/csp/';
|
||||
const mixedContent = `file=${path}file_CSP_web_manifest_mixed_content.html`;
|
||||
const server = 'file_csp_testserver.sjs';
|
||||
const secureURL = `https://example.com${path}${server}`;
|
||||
const tests = [
|
||||
// Trying to load mixed content in file_CSP_web_manifest_mixed_content.html
|
||||
// needs to result in an error.
|
||||
{
|
||||
expected: `Mixed Content Blocker prevents fetching manifest.`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
mixedContent
|
||||
];
|
||||
return `${secureURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(error) {
|
||||
// Check reason for error.
|
||||
const check = /blocked the loading of a resource/.test(error.message);
|
||||
ok(check, this.expected);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
//jscs:disable
|
||||
add_task(function*() {
|
||||
//jscs:enable
|
||||
for (let test of tests) {
|
||||
let tabOptions = {
|
||||
gBrowser: gBrowser,
|
||||
url: test.tabURL,
|
||||
};
|
||||
yield BrowserTestUtils.withNewTab(
|
||||
tabOptions,
|
||||
browser => testObtainingManifest(browser, test)
|
||||
);
|
||||
}
|
||||
|
||||
function* testObtainingManifest(aBrowser, aTest) {
|
||||
const obtainer = new ManifestObtainer();
|
||||
try {
|
||||
yield obtainer.obtainManifest(aBrowser);
|
||||
} catch (e) {
|
||||
aTest.run(e)
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<head>
|
||||
<link rel="manifest" href="file_CSP_web_manifest.json">
|
||||
</head>
|
||||
<h1>Support Page for Web Manifest Tests</h1>
|
|
@ -0,0 +1 @@
|
|||
{"name": "loaded"}
|
|
@ -0,0 +1 @@
|
|||
Access-Control-Allow-Origin: http://example.org
|
|
@ -0,0 +1,4 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<link rel="manifest" href="https://example.com:443/tests/dom/base/test/csp/file_CSP_web_manifest_https.json">
|
||||
<h1>Support Page for Web Manifest Tests</h1>
|
|
@ -0,0 +1 @@
|
|||
{"name": "loaded"}
|
|
@ -0,0 +1,9 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<head>
|
||||
<link
|
||||
rel="manifest"
|
||||
href="http://example.org/tests/dom/base/test/csp/file_csp_testserver.sjs?file=/test/dom/base/test/csp/file_CSP_web_manifest.json&cors=*">
|
||||
</head>
|
||||
<h1>Support Page for Web Manifest Tests</h1>
|
||||
<p>Used to try to load a resource over an insecure connection to trigger mixed content blocking.</p>
|
|
@ -0,0 +1,8 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<link rel="manifest"
|
||||
crossorigin
|
||||
href="//mochi.test:8888/tests/dom/base/test/csp/file_csp_testserver.sjs?file=/tests/dom/base/test/csp/file_CSP_web_manifest.json&cors=*">
|
||||
|
||||
<h1>Support Page for Web Manifest Tests</h1>
|
||||
<p>Loads a manifest from mochi.test:8888 with CORS set to "*".</p>
|
|
@ -22,6 +22,7 @@ function loadHTMLFromFile(path) {
|
|||
return testHTML;
|
||||
}
|
||||
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
var query = {};
|
||||
|
@ -30,16 +31,23 @@ function handleRequest(request, response)
|
|||
query[name] = unescape(value);
|
||||
});
|
||||
|
||||
var csp = unescape(query['csp']);
|
||||
var csp = (query['csp']) ? unescape(query['csp']) : "";
|
||||
var file = unescape(query['file']);
|
||||
var cors = unescape(query['cors']);
|
||||
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
// Deliver the CSP policy encoded in the URI
|
||||
response.setHeader("Content-Security-Policy", csp, false);
|
||||
|
||||
if(csp){
|
||||
response.setHeader("Content-Security-Policy", csp, false);
|
||||
}
|
||||
// Deliver the CORS header in the URI
|
||||
if(cors){
|
||||
response.setHeader("Access-Control-Allow-Origin", cors, false);
|
||||
}
|
||||
// Send HTML to test allowed/blocked behaviors
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
|
||||
response.write(loadHTMLFromFile(file));
|
||||
}
|
||||
|
|
|
@ -43,6 +43,13 @@ support-files =
|
|||
file_CSP_main.html
|
||||
file_CSP_main.html^headers^
|
||||
file_CSP_main.js
|
||||
file_CSP_web_manifest.html
|
||||
file_CSP_web_manifest_remote.html
|
||||
file_CSP_web_manifest_https.html
|
||||
file_CSP_web_manifest.json
|
||||
file_CSP_web_manifest.json^headers^
|
||||
file_CSP_web_manifest_https.json
|
||||
file_CSP_web_manifest_mixed_content.html
|
||||
file_bug836922_npolicies.html
|
||||
file_bug836922_npolicies.html^headers^
|
||||
file_bug836922_npolicies_ro_violation.sjs
|
||||
|
|
|
@ -37,4 +37,7 @@ MOCHITEST_CHROME_MANIFESTS += [
|
|||
'csp/chrome.ini',
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'browser.ini',
|
||||
'csp/browser.ini',
|
||||
]
|
||||
|
|
|
@ -168,6 +168,9 @@ InternalRequest::SetContentPolicyType(nsContentPolicyType aContentPolicyType)
|
|||
case nsIContentPolicy::TYPE_IMAGESET:
|
||||
mContext = RequestContext::Imageset;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_WEB_MANIFEST:
|
||||
mContext = RequestContext::Manifest;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unhandled nsContentPolicyType value");
|
||||
mContext = RequestContext::Internal;
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace dom {
|
|||
* import | Not supported by Gecko
|
||||
* internal | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER
|
||||
* location |
|
||||
* manifest |
|
||||
* manifest | TYPE_WEB_MANIFEST
|
||||
* object | TYPE_OBJECT
|
||||
* ping | TYPE_PING
|
||||
* plugin | TYPE_OBJECT_SUBREQUEST
|
||||
|
|
|
@ -20,7 +20,7 @@ interface nsIURI;
|
|||
|
||||
typedef unsigned short CSPDirective;
|
||||
|
||||
[scriptable, uuid(459fe61a-203e-4460-9ced-352a9bd3aa71)]
|
||||
[scriptable, uuid(059b94e3-45c2-4794-ac2a-5b66a66b5967)]
|
||||
interface nsIContentSecurityPolicy : nsISerializable
|
||||
{
|
||||
/**
|
||||
|
@ -48,6 +48,7 @@ interface nsIContentSecurityPolicy : nsISerializable
|
|||
const unsigned short BASE_URI_DIRECTIVE = 13;
|
||||
const unsigned short FORM_ACTION_DIRECTIVE = 14;
|
||||
const unsigned short REFERRER_DIRECTIVE = 15;
|
||||
const unsigned short WEB_MANIFEST_SRC_DIRECTIVE = 16;
|
||||
|
||||
/**
|
||||
* Accessor method for a read-only string version of the policy at a given
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
/*globals content, sendAsyncMessage, addMessageListener, Components*/
|
||||
'use strict';
|
||||
const {
|
||||
utils: Cu
|
||||
utils: Cu,
|
||||
classes: Cc,
|
||||
interfaces: Ci
|
||||
} = Components;
|
||||
const {
|
||||
ManifestProcessor
|
||||
|
@ -34,6 +36,7 @@ addMessageListener('DOM:ManifestObtainer:Obtain', async(function* (aMsg) {
|
|||
try {
|
||||
response.result = yield fetchManifest();
|
||||
} catch (err) {
|
||||
response.success = false;
|
||||
response.result = cloneError(err);
|
||||
}
|
||||
sendAsyncMessage('DOM:ManifestObtainer:Obtain', response);
|
||||
|
@ -64,6 +67,11 @@ function fetchManifest() {
|
|||
}
|
||||
// Throws on malformed URLs
|
||||
const manifestURL = new content.URL(elem.href, elem.baseURI);
|
||||
if (!canLoadManifest(elem)) {
|
||||
let msg = `Content Security Policy: The page's settings blocked the `;
|
||||
msg += `loading of a resource at ${elem.href}`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
const reqInit = {
|
||||
mode: 'cors'
|
||||
};
|
||||
|
@ -78,6 +86,21 @@ function fetchManifest() {
|
|||
});
|
||||
}
|
||||
|
||||
function canLoadManifest(aElem) {
|
||||
const contentPolicy = Cc['@mozilla.org/layout/content-policy;1']
|
||||
.getService(Ci.nsIContentPolicy);
|
||||
const mimeType = aElem.type || 'application/manifest+json';
|
||||
const elemURI = BrowserUtils.makeURI(
|
||||
aElem.href, aElem.ownerDocument.characterSet
|
||||
);
|
||||
const shouldLoad = contentPolicy.shouldLoad(
|
||||
Ci.nsIContentPolicy.TYPE_WEB_MANIFEST, elemURI,
|
||||
aElem.ownerDocument.documentURIObject,
|
||||
aElem, mimeType, null
|
||||
);
|
||||
return shouldLoad === Ci.nsIContentPolicy.ACCEPT;
|
||||
}
|
||||
|
||||
function processResponse(aResp, aContentWindow) {
|
||||
return spawn(function* () {
|
||||
const badStatus = aResp.status < 200 || aResp.status >= 300;
|
||||
|
|
|
@ -149,6 +149,9 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
|
|||
case nsIContentPolicy::TYPE_MEDIA:
|
||||
return nsIContentSecurityPolicy::MEDIA_SRC_DIRECTIVE;
|
||||
|
||||
case nsIContentPolicy::TYPE_WEB_MANIFEST:
|
||||
return nsIContentSecurityPolicy::WEB_MANIFEST_SRC_DIRECTIVE;
|
||||
|
||||
case nsIContentPolicy::TYPE_SUBDOCUMENT:
|
||||
return nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE;
|
||||
|
||||
|
@ -836,6 +839,10 @@ nsCSPDirective::toDomCSPStruct(mozilla::dom::CSP& outCSP) const
|
|||
outCSP.mFrame_ancestors.Value() = srcs;
|
||||
return;
|
||||
|
||||
case nsIContentSecurityPolicy::WEB_MANIFEST_SRC_DIRECTIVE:
|
||||
outCSP.mManifest_src.Construct();
|
||||
outCSP.mManifest_src.Value() = srcs;
|
||||
return;
|
||||
// not supporting REFLECTED_XSS_DIRECTIVE
|
||||
|
||||
case nsIContentSecurityPolicy::BASE_URI_DIRECTIVE:
|
||||
|
|
|
@ -64,8 +64,11 @@ void CSP_LogMessage(const nsAString& aMessage,
|
|||
|
||||
// these strings map to the CSPDirectives in nsIContentSecurityPolicy
|
||||
// NOTE: When implementing a new directive, you will need to add it here but also
|
||||
// add a corresponding entry to the constants in nsIContentSecurityPolicy.idl and
|
||||
// also create an entry for the new directive in nsCSPDirective::toDomCSPStruct().
|
||||
// add a corresponding entry to the constants in nsIContentSecurityPolicy.idl
|
||||
// and also create an entry for the new directive in
|
||||
// nsCSPDirective::toDomCSPStruct() and add it to CSPDictionaries.webidl.
|
||||
// Order of elements below important! Make sure it matches the order as in
|
||||
// nsIContentSecurityPolicy.idl
|
||||
static const char* CSPStrDirectives[] = {
|
||||
"-error-", // NO_DIRECTIVE
|
||||
"default-src", // DEFAULT_SRC_DIRECTIVE
|
||||
|
@ -82,7 +85,8 @@ static const char* CSPStrDirectives[] = {
|
|||
"reflected-xss", // REFLECTED_XSS_DIRECTIVE
|
||||
"base-uri", // BASE_URI_DIRECTIVE
|
||||
"form-action", // FORM_ACTION_DIRECTIVE
|
||||
"referrer" // REFERRER_DIRECTIVE
|
||||
"referrer", // REFERRER_DIRECTIVE
|
||||
"manifest-src" // MANIFEST_SRC_DIRECTIVE
|
||||
};
|
||||
|
||||
inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)
|
||||
|
|
|
@ -439,6 +439,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
|||
case TYPE_SCRIPT:
|
||||
case TYPE_STYLESHEET:
|
||||
case TYPE_SUBDOCUMENT:
|
||||
case TYPE_WEB_MANIFEST:
|
||||
case TYPE_XBL:
|
||||
case TYPE_XMLHTTPREQUEST:
|
||||
case TYPE_XSLT:
|
||||
|
|
|
@ -24,6 +24,7 @@ dictionary CSP {
|
|||
sequence<DOMString> base-uri;
|
||||
sequence<DOMString> form-action;
|
||||
sequence<DOMString> referrer;
|
||||
sequence<DOMString> manifest-src;
|
||||
};
|
||||
|
||||
dictionary CSPPolicies {
|
||||
|
|
|
@ -39,7 +39,11 @@ static const char *kTypeString[] = {"other",
|
|||
"media",
|
||||
"websocket",
|
||||
"csp_report",
|
||||
"xslt"};
|
||||
"xslt",
|
||||
"beacon",
|
||||
"fetch",
|
||||
"imageset",
|
||||
"manifest"};
|
||||
|
||||
#define NUMBER_OF_TYPES MOZ_ARRAY_LENGTH(kTypeString)
|
||||
uint8_t nsContentBlocker::mBehaviorPref[NUMBER_OF_TYPES];
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#define APPLICATION_OLEOBJECT2 "application/x-oleobject"
|
||||
#define APPLICATION_JAVAARCHIVE "application/java-archive"
|
||||
#define APPLICATION_MARIMBA "application/marimba"
|
||||
#define APPLICATION_WEB_MANIFEST "application/manifest+json"
|
||||
#define APPLICATION_XMARIMBA "application/x-marimba"
|
||||
#define APPLICATION_XPINSTALL "application/x-xpinstall"
|
||||
#define APPLICATION_XML "application/xml"
|
||||
|
|
Загрузка…
Ссылка в новой задаче