Bug 1797086 add upgrade-insecure-requests to the base csp for MV3 r=robwu

Differential Revision: https://phabricator.services.mozilla.com/D163046
This commit is contained in:
Shane Caraveo 2022-11-30 22:57:18 +00:00
Родитель 014dfde354
Коммит e954421490
13 изменённых файлов: 208 добавлений и 12 удалений

Просмотреть файл

@ -3381,7 +3381,7 @@ pref("extensions.webcompat-reporter.newIssueEndpoint", "https://webcompat.com/is
pref("extensions.webextensions.base-content-security-policy", "script-src 'self' https://* http://localhost:* http://127.0.0.1:* moz-extension: blob: filesystem: 'unsafe-eval' 'wasm-unsafe-eval' 'unsafe-inline';");
pref("extensions.webextensions.base-content-security-policy.v3", "script-src 'self' 'wasm-unsafe-eval';");
pref("extensions.webextensions.default-content-security-policy", "script-src 'self' 'wasm-unsafe-eval';");
pref("extensions.webextensions.default-content-security-policy.v3", "script-src 'self';");
pref("extensions.webextensions.default-content-security-policy.v3", "script-src 'self'; upgrade-insecure-requests;");
pref("network.buffer.cache.count", 24);

Просмотреть файл

@ -52,7 +52,7 @@ using dom::Promise;
#define DEFAULT_CSP_PREF_V3 \
"extensions.webextensions.default-content-security-policy.v3"
#define DEFAULT_DEFAULT_CSP_V3 "script-src 'self';"
#define DEFAULT_DEFAULT_CSP_V3 "script-src 'self'; upgrade-insecure-requests;"
#define OBS_TOPIC_PRELOAD_SCRIPT "web-extension-preload-content-script"
#define OBS_TOPIC_LOAD_SCRIPT "web-extension-load-content-script"

Просмотреть файл

@ -428,6 +428,23 @@ ExtensionTestCommon = class ExtensionTestCommon {
data.useServiceWorker = ExtensionTestCommon.isInBackgroundServiceWorkerTests();
}
// allowInsecureRequests is a shortcut to removing upgrade-insecure-requests from default csp.
if (data.allowInsecureRequests) {
// upgrade-insecure-requests is only added automatically to MV3.
// This flag is therefore not needed in MV2.
if (manifest.manifest_version < 3) {
throw new Error("allowInsecureRequests requires manifest_version 3");
}
if (manifest.content_security_policy) {
throw new Error(
"allowInsecureRequests cannot be used with manifest.content_security_policy"
);
}
manifest.content_security_policy = {
extension_pages: `script-src 'self'`,
};
}
if (data.background) {
let bgScript = Services.uuid.generateUUID().number + ".js";

Просмотреть файл

@ -32,9 +32,19 @@ add_task(async function upgradeScheme_with_dnr() {
let extension = ExtensionTestUtils.loadExtension({
async background() {
await browser.declarativeNetRequest.updateSessionRules({
addRules: [{ id: 1, condition: {}, action: { type: "upgradeScheme" } }],
addRules: [{ id: 1, condition: { requestDomains: ["example.com"] }, action: { type: "upgradeScheme" } }],
});
let sanityCheckResponse = await fetch(
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://example.net/tests/toolkit/components/extensions/test/mochitest/file_sample.txt"
);
browser.test.assertEq(
"https://example.net/tests/toolkit/components/extensions/test/mochitest/file_sample.txt",
sanityCheckResponse.url,
"non-matching request should not be upgraded"
);
let res = await fetch(
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://example.com/tests/toolkit/components/extensions/test/mochitest/file_sample.txt"
@ -55,6 +65,7 @@ add_task(async function upgradeScheme_with_dnr() {
// Note: host_permissions missing. upgradeScheme should not need it.
permissions: ["declarativeNetRequest"],
},
allowInsecureRequests: true,
});
await extension.startup();
await extension.awaitMessage("dnr_registered");

Просмотреть файл

@ -0,0 +1,74 @@
"use strict";
const server = createHttpServer({ hosts: ["example.com"] });
server.registerPathHandler("/", (req, res) => {
res.write("ok");
});
add_setup(async () => {
Services.prefs.setBoolPref("extensions.manifestV3.enabled", true);
});
add_task(async function test_csp_upgrade() {
async function background() {
browser.webRequest.onBeforeRequest.addListener(
details => {
browser.test.assertEq(
details.url,
"https://example.com/",
"request upgraded and sent"
);
browser.test.notifyPass();
return { cancel: true };
},
{
urls: ["https://example.com/*"],
},
["blocking"]
);
await browser.test.assertRejects(
fetch("http://example.com/"),
"NetworkError when attempting to fetch resource.",
"request was upgraded"
);
}
let extension = ExtensionTestUtils.loadExtension({
background,
temporarilyInstalled: true,
manifest: {
manifest_version: 3,
granted_host_permissions: true,
host_permissions: ["*://example.com/*"],
permissions: ["webRequest", "webRequestBlocking"],
},
});
await extension.startup();
await extension.awaitFinish();
await extension.unload();
});
add_task(async function test_csp_noupgrade() {
async function background() {
let req = await fetch("http://example.com/");
browser.test.assertEq(
req.url,
"http://example.com/",
"request not upgraded"
);
browser.test.notifyPass();
}
let extension = ExtensionTestUtils.loadExtension({
background,
temporarilyInstalled: true,
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
granted_host_permissions: true,
host_permissions: ["*://example.com/*"],
},
});
await extension.startup();
await extension.awaitFinish();
await extension.unload();
});

Просмотреть файл

@ -219,6 +219,7 @@ add_task(async function getTabIdForChannelWrapper_only_called_when_needed() {
let extension = ExtensionTestUtils.loadExtension({
background,
useAddonManager: "temporary", // for reload and granted_host_permissions.
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
host_permissions: ["*://from/*"],

Просмотреть файл

@ -51,6 +51,7 @@ add_task(async function block_request_with_dnr() {
let extension = ExtensionTestUtils.loadExtension({
background,
temporarilyInstalled: true, // Needed for granted_host_permissions
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
granted_host_permissions: true,
@ -194,6 +195,7 @@ add_task(async function block_request_with_webRequest_after_allow_with_dnr() {
let extension = ExtensionTestUtils.loadExtension({
background,
temporarilyInstalled: true, // Needed for granted_host_permissions
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
granted_host_permissions: true,

Просмотреть файл

@ -108,6 +108,7 @@ add_task(async function block_request_with_dnr() {
browser.test.sendMessage("tested_dnr_block");
}
let extension = ExtensionTestUtils.loadExtension({
allowInsecureRequests: true,
background,
manifest: {
manifest_version: 3,
@ -156,6 +157,7 @@ add_task(async function block_with_declarativeNetRequestWithHostAccess() {
browser.test.sendMessage("dnr_registered");
},
temporarilyInstalled: true, // Needed for granted_host_permissions
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
granted_host_permissions: true,
@ -233,6 +235,7 @@ add_task(async function upgradeScheme_declarativeNetRequestWithHostAccess() {
browser.test.sendMessage("tested_dnr_upgradeScheme");
},
temporarilyInstalled: true, // Needed for granted_host_permissions.
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
granted_host_permissions: true,
@ -336,6 +339,7 @@ add_task(async function redirect_request_with_dnr() {
let extension = ExtensionTestUtils.loadExtension({
background,
temporarilyInstalled: true, // Needed for granted_host_permissions
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
granted_host_permissions: true,
@ -420,6 +424,7 @@ add_task(async function redirect_request_with_dnr_cors_preflight() {
let extension = ExtensionTestUtils.loadExtension({
background,
temporarilyInstalled: true, // Needed for granted_host_permissions
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
granted_host_permissions: true,
@ -525,6 +530,7 @@ add_task(async function redirect_request_with_dnr_multiple_hops() {
let extension = ExtensionTestUtils.loadExtension({
background,
temporarilyInstalled: true, // Needed for granted_host_permissions
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
granted_host_permissions: true,
@ -582,6 +588,7 @@ add_task(async function redirect_request_with_dnr_with_redirect_loop() {
let extension = ExtensionTestUtils.loadExtension({
background,
temporarilyInstalled: true, // Needed for granted_host_permissions
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
granted_host_permissions: true,
@ -663,6 +670,7 @@ add_task(async function redirect_request_with_dnr_to_extensionPath() {
let extension = ExtensionTestUtils.loadExtension({
background,
temporarilyInstalled: true, // Needed for granted_host_permissions
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
granted_host_permissions: true,

Просмотреть файл

@ -20,6 +20,7 @@ const makeExtension = ({ manifest: manifestProps, ...otherProps }) => {
granted_host_permissions: true,
...manifestProps,
},
allowInsecureRequests: true,
temporarilyInstalled: true,
...otherProps,
});

Просмотреть файл

@ -148,3 +148,43 @@ add_task(async function test_policy_temporarilyInstalled() {
await runTest("temporary");
await runTest("permanent");
});
add_task(async function test_manifest_allowInsecureRequests() {
Services.prefs.setBoolPref("extensions.manifestV3.enabled", true);
let extensionData = {
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
equal(
extension.extension.manifest.content_security_policy.extension_pages,
`script-src 'self'`,
"insecure allowed"
);
await extension.unload();
Services.prefs.clearUserPref("extensions.manifestV3.enabled");
});
add_task(async function test_manifest_allowInsecureRequests_throws() {
Services.prefs.setBoolPref("extensions.manifestV3.enabled", true);
let extensionData = {
allowInsecureRequests: true,
manifest: {
manifest_version: 3,
content_security_policy: {
extension_pages: `script-src 'self'`,
},
},
};
await Assert.throws(
() => ExtensionTestUtils.loadExtension(extensionData),
/allowInsecureRequests cannot be used with manifest.content_security_policy/,
"allowInsecureRequests with content_security_policy cannot be loaded"
);
Services.prefs.clearUserPref("extensions.manifestV3.enabled");
});

Просмотреть файл

@ -91,7 +91,7 @@ add_task(async function test_wasm_v3_blocked_by_default() {
equal(await extension.awaitMessage("result"), "blocked");
equal(
await extension.awaitMessage("violated_csp"),
"script-src 'self'",
"script-src 'self'; upgrade-insecure-requests",
"WASM usage violates default CSP in MV3"
);
await extension.unload();

Просмотреть файл

@ -24,7 +24,12 @@ async function testWebSocketInFrameUpgraded() {
// testIframe = true: open WebSocket from iframe (original test case).
// testIframe = false: open WebSocket from content script.
async function test_webSocket({ manifest_version, useIframe }) {
async function test_webSocket({
manifest_version,
useIframe,
content_security_policy,
expectUpgrade,
}) {
let web_accessible_resources =
manifest_version == 2
? ["frame.html"]
@ -37,6 +42,7 @@ async function test_webSocket({ manifest_version, useIframe }) {
host_permissions: ["<all_urls>"],
granted_host_permissions: true,
web_accessible_resources,
content_security_policy,
content_scripts: [
{
matches: ["http://*/plain.html"],
@ -81,10 +87,11 @@ async function test_webSocket({ manifest_version, useIframe }) {
let contentPage = await ExtensionTestUtils.loadContentPage(pageURL);
let { ws_scheme, originHeader } = await extension.awaitMessage("ws_request");
if (useIframe || manifest_version == 2) {
Assert.equal(ws_scheme, "ws:", "ws:-request should not have been upgraded");
if (expectUpgrade) {
Assert.equal(ws_scheme, "wss:", "ws:-request should have been upgraded");
} else {
Assert.equal(ws_scheme, "wss:", "WebSocket affected by page CSP in MV3");
Assert.equal(ws_scheme, "ws:", "ws:-request should not have been upgraded");
}
if (useIframe) {
@ -104,18 +111,52 @@ async function test_webSocket({ manifest_version, useIframe }) {
await extension.unload();
}
// Page CSP does not affect extension iframes.
add_task(async function test_webSocket_upgrade_iframe_mv2() {
await test_webSocket({ manifest_version: 2, useIframe: true });
await test_webSocket({
manifest_version: 2,
useIframe: true,
expectUpgrade: false,
});
});
// Page CSP does not affect extension iframes, however upgrade-insecure-requests causes this
// request to be upgraded in the iframe.
add_task(async function test_webSocket_upgrade_iframe_mv3() {
await test_webSocket({ manifest_version: 3, useIframe: true });
await test_webSocket({
manifest_version: 3,
useIframe: true,
expectUpgrade: true,
});
});
// Test that removing upgrade-insecure-requests allows http request in the iframe.
add_task(async function test_webSocket_noupgrade_iframe_mv3() {
let content_security_policy = {
extension_pages: `script-src 'self'`,
};
await test_webSocket({
manifest_version: 3,
content_security_policy,
useIframe: true,
expectUpgrade: false,
});
});
// Page CSP does not affect MV2 in the content script.
add_task(async function test_webSocket_upgrade_in_contentscript_mv2() {
await test_webSocket({ manifest_version: 2, useIframe: false });
await test_webSocket({
manifest_version: 2,
useIframe: false,
expectUpgrade: false,
});
});
// Page CSP affects MV3 in the content script.
add_task(async function test_webSocket_upgrade_in_contentscript_mv3() {
await test_webSocket({ manifest_version: 3, useIframe: false });
await test_webSocket({
manifest_version: 3,
useIframe: false,
expectUpgrade: true,
});
});

Просмотреть файл

@ -113,6 +113,7 @@ skip-if =
os == "android" # Containers are not exposed to android.
[test_ext_cors_mozextension.js]
[test_ext_csp_frame_ancestors.js]
[test_ext_csp_upgrade_requests.js]
[test_ext_debugging_utils.js]
[test_ext_dnr_allowAllRequests.js]
[test_ext_dnr_api.js]