Force CSP inheritance for redirections to data: URIs on Gecko pre-69.
This commit is contained in:
parent
c44ab6f8aa
commit
d8332adc4e
|
@ -25,6 +25,8 @@ function ReportingCSP(reportURI, reportGroup) {
|
||||||
patchHeaders(responseHeaders, capabilities) {
|
patchHeaders(responseHeaders, capabilities) {
|
||||||
let header = null;
|
let header = null;
|
||||||
let needsReportTo = REPORT_TO_SUPPORTED;
|
let needsReportTo = REPORT_TO_SUPPORTED;
|
||||||
|
|
||||||
|
let blocker = capabilities && this.buildFromCapabilities(capabilities);
|
||||||
for (let h of responseHeaders) {
|
for (let h of responseHeaders) {
|
||||||
if (this.isMine(h)) {
|
if (this.isMine(h)) {
|
||||||
header = h;
|
header = h;
|
||||||
|
@ -32,10 +34,16 @@ function ReportingCSP(reportURI, reportGroup) {
|
||||||
} else if (needsReportTo &&
|
} else if (needsReportTo &&
|
||||||
h.name === REPORT_TO.name && h.value === REPORT_TO.value) {
|
h.name === REPORT_TO.name && h.value === REPORT_TO.value) {
|
||||||
needsReportTo = false;
|
needsReportTo = false;
|
||||||
|
} else if (blocker && /^(Location|Refresh)$/i.test(h.name)) {
|
||||||
|
let url = /^R/i.test(h.name)
|
||||||
|
? h.value.replace(/^[^,;]*[,;]url[^\w=]*=\s*/i, "") : h.value;
|
||||||
|
let patched = CSP.patchDataURI(url, blocker);
|
||||||
|
if (patched !== url) {
|
||||||
|
h.value = h.value.slice(0, -url.length) + patched;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let blocker = capabilities && this.buildFromCapabilities(capabilities);
|
|
||||||
if (blocker) {
|
if (blocker) {
|
||||||
if (needsReportTo) {
|
if (needsReportTo) {
|
||||||
responseHeaders.push(REPORT_TO);
|
responseHeaders.push(REPORT_TO);
|
||||||
|
|
|
@ -305,9 +305,10 @@ var RequestGuard = (() => {
|
||||||
normalizeRequest(request);
|
normalizeRequest(request);
|
||||||
try {
|
try {
|
||||||
let redirected = initPendingRequest(request);
|
let redirected = initPendingRequest(request);
|
||||||
let {policy} = ns;
|
let {policy} = ns
|
||||||
let policyType = policyTypesMap[request.type];
|
let {type} = request;
|
||||||
if (policyType) {
|
if (type in policyTypesMap) {
|
||||||
|
let policyType = policyTypesMap[type];
|
||||||
let {url, originUrl, documentUrl, tabId} = request;
|
let {url, originUrl, documentUrl, tabId} = request;
|
||||||
let isFetch = "fetch" === policyType;
|
let isFetch = "fetch" === policyType;
|
||||||
|
|
||||||
|
@ -327,7 +328,7 @@ var RequestGuard = (() => {
|
||||||
|
|
||||||
if (/^(?:data|blob):/.test(url)) {
|
if (/^(?:data|blob):/.test(url)) {
|
||||||
request._dataUrl = url;
|
request._dataUrl = url;
|
||||||
request.url = url = documentUrl;
|
request.url = url = documentUrl || originUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
let allowed = Sites.isInternal(url);
|
let allowed = Sites.isInternal(url);
|
||||||
|
@ -340,10 +341,19 @@ var RequestGuard = (() => {
|
||||||
allowed = !ns.isEnforced(tabId);
|
allowed = !ns.isEnforced(tabId);
|
||||||
}
|
}
|
||||||
if (!allowed) {
|
if (!allowed) {
|
||||||
allowed = intersectCapabilities(
|
let capabilities = intersectCapabilities(
|
||||||
policy.get(url, documentUrl).perms,
|
policy.get(url, documentUrl).perms,
|
||||||
request
|
request);
|
||||||
).has(policyType);
|
allowed = !policyType || capabilities.has(policyType);
|
||||||
|
if (allowed && request._dataUrl && type.endsWith("frame")) {
|
||||||
|
let blocker = csp.buildFromCapabilities(capabilities);
|
||||||
|
if (blocker) {
|
||||||
|
let redirectUrl = CSP.patchDataURI(request._dataUrl, blocker);
|
||||||
|
if (redirectUrl !== request._dataUrl) {
|
||||||
|
return {redirectUrl};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Content.reportTo(request, allowed, policyType);
|
Content.reportTo(request, allowed, policyType);
|
||||||
|
|
|
@ -21,3 +21,18 @@ class CSP {
|
||||||
|
|
||||||
CSP.isEmbedType = type => /\b(?:application|video|audio)\b/.test(type) && type !== "application/xhtml+xml";
|
CSP.isEmbedType = type => /\b(?:application|video|audio)\b/.test(type) && type !== "application/xhtml+xml";
|
||||||
CSP.headerName = "content-security-policy";
|
CSP.headerName = "content-security-policy";
|
||||||
|
CSP.patchDataURI = (uri, blocker) => {
|
||||||
|
let parts = /^data:(?:[^,;]*ml)(;[^,]*)?,/i.exec(uri);
|
||||||
|
if (!(blocker && parts)) {
|
||||||
|
// not an interesting data: URI, return as it is
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
if (parts[1]) {
|
||||||
|
// extra encoding info, let's bailout (better safe than sorry)
|
||||||
|
return "data:";
|
||||||
|
}
|
||||||
|
// It's a HTML/XML page, let's prepend our CSP blocker to the document
|
||||||
|
let patch = parts[0] + encodeURIComponent(
|
||||||
|
`<meta http-equiv="${CSP.headerName}" content="${blocker}">`);
|
||||||
|
return uri.startsWith(patch) ? uri : patch + uri.substring(parts[0].length);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue