forked from mirrors/gecko-dev
322 lines
9.5 KiB
JavaScript
322 lines
9.5 KiB
JavaScript
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* vim: set sts=2 sw=2 et tw=80: */
|
|
"use strict";
|
|
|
|
const cps = Cc["@mozilla.org/addons/content-policy;1"].getService(
|
|
Ci.nsIAddonContentPolicy
|
|
);
|
|
|
|
add_task(async function test_csp_validator_flags() {
|
|
let checkPolicy = (policy, flags, expectedResult) => {
|
|
info(`Checking policy: ${policy}`);
|
|
|
|
let result = cps.validateAddonCSP(policy, flags);
|
|
equal(result, expectedResult);
|
|
};
|
|
|
|
let flags = Ci.nsIAddonContentPolicy;
|
|
|
|
checkPolicy(
|
|
"default-src 'self'; script-src 'self' http://localhost",
|
|
0,
|
|
"\u2018script-src\u2019 directive contains a forbidden http: protocol source",
|
|
"localhost disallowed"
|
|
);
|
|
checkPolicy(
|
|
"default-src 'self'; script-src 'self' http://localhost",
|
|
flags.CSP_ALLOW_LOCALHOST,
|
|
null,
|
|
"localhost allowed"
|
|
);
|
|
|
|
checkPolicy(
|
|
"default-src 'self'; script-src 'self' 'unsafe-eval'",
|
|
0,
|
|
"\u2018script-src\u2019 directive contains a forbidden 'unsafe-eval' keyword",
|
|
"eval disallowed"
|
|
);
|
|
checkPolicy(
|
|
"default-src 'self'; script-src 'self' 'unsafe-eval'",
|
|
flags.CSP_ALLOW_EVAL,
|
|
null,
|
|
"eval allowed"
|
|
);
|
|
|
|
checkPolicy(
|
|
"default-src 'self'; script-src 'self' 'wasm-unsafe-eval'",
|
|
0,
|
|
"\u2018script-src\u2019 directive contains a forbidden 'wasm-unsafe-eval' keyword",
|
|
"wasm disallowed"
|
|
);
|
|
checkPolicy(
|
|
"default-src 'self'; script-src 'self' 'wasm-unsafe-eval'",
|
|
flags.CSP_ALLOW_WASM,
|
|
null,
|
|
"wasm allowed"
|
|
);
|
|
checkPolicy(
|
|
"default-src 'self'; script-src 'self' 'unsafe-eval' 'wasm-unsafe-eval'",
|
|
flags.CSP_ALLOW_EVAL,
|
|
null,
|
|
"wasm and eval allowed"
|
|
);
|
|
|
|
checkPolicy(
|
|
"default-src 'self'; script-src 'self' https://example.com",
|
|
0,
|
|
"\u2018script-src\u2019 directive contains a forbidden https: protocol source",
|
|
"remote disallowed"
|
|
);
|
|
checkPolicy(
|
|
"default-src 'self'; script-src 'self' https://example.com",
|
|
flags.CSP_ALLOW_REMOTE,
|
|
null,
|
|
"remote allowed"
|
|
);
|
|
});
|
|
|
|
add_task(async function test_csp_validator() {
|
|
let checkPolicy = (policy, expectedResult) => {
|
|
info(`Checking policy: ${policy}`);
|
|
|
|
let result = cps.validateAddonCSP(
|
|
policy,
|
|
Ci.nsIAddonContentPolicy.CSP_ALLOW_ANY
|
|
);
|
|
equal(result, expectedResult);
|
|
};
|
|
|
|
checkPolicy("script-src 'self';", null);
|
|
|
|
// In the past, object-src was required to be secure and defaulted to 'self'.
|
|
// But that is no longer required (see bug 1766881).
|
|
checkPolicy("script-src 'self'; object-src 'self';", null);
|
|
checkPolicy("script-src 'self'; object-src https:;", null);
|
|
|
|
let hash =
|
|
"'sha256-NjZhMDQ1YjQ1MjEwMmM1OWQ4NDBlYzA5N2Q1OWQ5NDY3ZTEzYTNmMzRmNjQ5NGU1MzlmZmQzMmMxYmIzNWYxOCAgLQo='";
|
|
|
|
checkPolicy(
|
|
`script-src 'self' https://com https://*.example.com moz-extension://09abcdef blob: filesystem: ${hash} 'unsafe-eval'; ` +
|
|
`object-src 'self' https://com https://*.example.com moz-extension://09abcdef blob: filesystem: ${hash}`,
|
|
null
|
|
);
|
|
|
|
checkPolicy(
|
|
"",
|
|
"Policy is missing a required \u2018script-src\u2019 directive"
|
|
);
|
|
|
|
checkPolicy(
|
|
"object-src 'none';",
|
|
"Policy is missing a required \u2018script-src\u2019 directive"
|
|
);
|
|
|
|
checkPolicy(
|
|
"default-src 'self' http:",
|
|
"Policy is missing a required \u2018script-src\u2019 directive",
|
|
"A strict default-src is required as a fallback if script-src is missing"
|
|
);
|
|
|
|
checkPolicy(
|
|
"default-src 'self' http:; script-src 'self'",
|
|
null,
|
|
"A valid script-src removes the need for a strict default-src fallback"
|
|
);
|
|
|
|
checkPolicy(
|
|
"default-src 'self'",
|
|
null,
|
|
"A valid default-src should count as a valid script-src"
|
|
);
|
|
|
|
checkPolicy(
|
|
"default-src 'self'; script-src 'self'",
|
|
null,
|
|
"A valid default-src should count as a valid script-src"
|
|
);
|
|
|
|
checkPolicy(
|
|
"default-src 'self'; script-src http://example.com",
|
|
"\u2018script-src\u2019 directive contains a forbidden http: protocol source",
|
|
"A valid default-src should not allow an invalid script-src directive"
|
|
);
|
|
|
|
checkPolicy(
|
|
"script-src 'none'",
|
|
"\u2018script-src\u2019 must include the source 'self'"
|
|
);
|
|
|
|
checkPolicy(
|
|
"script-src 'self' 'unsafe-inline'",
|
|
"\u2018script-src\u2019 directive contains a forbidden 'unsafe-inline' keyword"
|
|
);
|
|
|
|
// Localhost is always valid
|
|
for (let src of [
|
|
"http://localhost",
|
|
"https://localhost",
|
|
"http://127.0.0.1",
|
|
"https://127.0.0.1",
|
|
]) {
|
|
checkPolicy(`script-src 'self' ${src};`, null);
|
|
}
|
|
|
|
let directives = ["script-src", "worker-src"];
|
|
|
|
for (let [directive, other] of [directives, directives.slice().reverse()]) {
|
|
for (let src of ["https://*", "https://*.blogspot.com", "https://*"]) {
|
|
checkPolicy(
|
|
`${directive} 'self' ${src}; ${other} 'self';`,
|
|
`https: wildcard sources in \u2018${directive}\u2019 directives must include at least one non-generic sub-domain (e.g., *.example.com rather than *.com)`
|
|
);
|
|
}
|
|
|
|
for (let protocol of ["http", "https"]) {
|
|
checkPolicy(
|
|
`${directive} 'self' ${protocol}:; ${other} 'self';`,
|
|
`${protocol}: protocol requires a host in \u2018${directive}\u2019 directives`
|
|
);
|
|
}
|
|
|
|
checkPolicy(
|
|
`${directive} 'self' http://example.com; ${other} 'self';`,
|
|
`\u2018${directive}\u2019 directive contains a forbidden http: protocol source`
|
|
);
|
|
|
|
for (let protocol of ["ftp", "meh"]) {
|
|
checkPolicy(
|
|
`${directive} 'self' ${protocol}:; ${other} 'self';`,
|
|
`\u2018${directive}\u2019 directive contains a forbidden ${protocol}: protocol source`
|
|
);
|
|
}
|
|
|
|
checkPolicy(
|
|
`${directive} 'self' 'nonce-01234'; ${other} 'self';`,
|
|
`\u2018${directive}\u2019 directive contains a forbidden 'nonce-*' keyword`
|
|
);
|
|
}
|
|
});
|
|
|
|
add_task(async function test_csp_validator_extension_pages() {
|
|
let checkPolicy = (policy, expectedResult) => {
|
|
info(`Checking policy: ${policy}`);
|
|
|
|
// While Schemas.sys.mjs uses Ci.nsIAddonContentPolicy.CSP_ALLOW_WASM, we
|
|
// don't pass that here because we are only verifying that remote scripts are
|
|
// blocked here.
|
|
let result = cps.validateAddonCSP(policy, 0);
|
|
equal(result, expectedResult);
|
|
};
|
|
|
|
checkPolicy("script-src 'self';", null);
|
|
checkPolicy("script-src 'self'; worker-src 'none'", null);
|
|
checkPolicy("script-src 'self'; worker-src 'self'", null);
|
|
|
|
// In the past, object-src was required to be secure and defaulted to 'self'.
|
|
// But that is no longer required (see bug 1766881).
|
|
checkPolicy("script-src 'self'; object-src 'self';", null);
|
|
checkPolicy("script-src 'self'; object-src https:;", null);
|
|
|
|
let hash =
|
|
"'sha256-NjZhMDQ1YjQ1MjEwMmM1OWQ4NDBlYzA5N2Q1OWQ5NDY3ZTEzYTNmMzRmNjQ5NGU1MzlmZmQzMmMxYmIzNWYxOCAgLQo='";
|
|
|
|
checkPolicy(
|
|
`script-src 'self' moz-extension://09abcdef blob: filesystem: ${hash}; `,
|
|
null
|
|
);
|
|
|
|
for (let policy of ["", "script-src-elem 'none';", "worker-src 'none';"]) {
|
|
checkPolicy(
|
|
policy,
|
|
"Policy is missing a required \u2018script-src\u2019 directive"
|
|
);
|
|
}
|
|
|
|
checkPolicy(
|
|
"default-src 'self' http:; script-src 'self'",
|
|
null,
|
|
"A valid script-src removes the need for a strict default-src fallback"
|
|
);
|
|
|
|
checkPolicy(
|
|
"default-src 'self'",
|
|
null,
|
|
"A valid default-src should count as a valid script-src"
|
|
);
|
|
|
|
for (let directive of ["script-src", "worker-src"]) {
|
|
checkPolicy(
|
|
`default-src 'self'; ${directive} 'self'`,
|
|
null,
|
|
`A valid default-src should count as a valid ${directive}`
|
|
);
|
|
checkPolicy(
|
|
`default-src 'self'; ${directive} http://example.com`,
|
|
`\u2018${directive}\u2019 directive contains a forbidden http: protocol source`,
|
|
`A valid default-src should not allow an invalid ${directive} directive`
|
|
);
|
|
}
|
|
|
|
checkPolicy(
|
|
"script-src 'none'",
|
|
"\u2018script-src\u2019 must include the source 'self'"
|
|
);
|
|
|
|
checkPolicy(
|
|
"script-src 'self' 'unsafe-inline';",
|
|
"\u2018script-src\u2019 directive contains a forbidden 'unsafe-inline' keyword"
|
|
);
|
|
|
|
checkPolicy(
|
|
"script-src 'self' 'unsafe-eval';",
|
|
"\u2018script-src\u2019 directive contains a forbidden 'unsafe-eval' keyword"
|
|
);
|
|
|
|
// Localhost is invalid
|
|
for (let src of [
|
|
"http://localhost",
|
|
"https://localhost",
|
|
"http://127.0.0.1",
|
|
"https://127.0.0.1",
|
|
]) {
|
|
const protocol = src.split(":")[0];
|
|
checkPolicy(
|
|
`script-src 'self' ${src};`,
|
|
`\u2018script-src\u2019 directive contains a forbidden ${protocol}: protocol source`
|
|
);
|
|
}
|
|
|
|
let directives = ["script-src", "worker-src"];
|
|
|
|
for (let [directive, other] of [directives, directives.slice().reverse()]) {
|
|
for (let protocol of ["http", "https"]) {
|
|
checkPolicy(
|
|
`${directive} 'self' ${protocol}:; ${other} 'self';`,
|
|
`${protocol}: protocol requires a host in \u2018${directive}\u2019 directives`
|
|
);
|
|
}
|
|
|
|
checkPolicy(
|
|
`${directive} 'self' https://example.com; ${other} 'self';`,
|
|
`\u2018${directive}\u2019 directive contains a forbidden https: protocol source`
|
|
);
|
|
|
|
checkPolicy(
|
|
`${directive} 'self' http://example.com; ${other} 'self';`,
|
|
`\u2018${directive}\u2019 directive contains a forbidden http: protocol source`
|
|
);
|
|
|
|
for (let protocol of ["ftp", "meh"]) {
|
|
checkPolicy(
|
|
`${directive} 'self' ${protocol}:; ${other} 'self';`,
|
|
`\u2018${directive}\u2019 directive contains a forbidden ${protocol}: protocol source`
|
|
);
|
|
}
|
|
|
|
checkPolicy(
|
|
`${directive} 'self' 'nonce-01234'; ${other} 'self';`,
|
|
`\u2018${directive}\u2019 directive contains a forbidden 'nonce-*' keyword`
|
|
);
|
|
}
|
|
});
|