Simplified CSP HTTP header injection, avoiding report-to until actually supported by browsers.

This commit is contained in:
hackademix 2018-10-06 17:05:14 +02:00
parent c9c7b7aefe
commit 209d50b0c1
2 changed files with 25 additions and 29 deletions

View File

@ -1,6 +1,13 @@
"use strict";
function ReportingCSP(reportURI, reportGroup) {
const REPORT_TO_SUPPORTED = false;
// TODO: figure out if we're running on a browser supporting the report-to
// CSP directive, breaking report-uri, see
// 1. https://www.w3.org/TR/CSP3/#directive-report-uri
// 2. https://bugs.chromium.org/p/chromium/issues/detail?id=726634
// 3. https://bugzilla.mozilla.org/show_bug.cgi?id=1391243
const REPORT_TO = {
name: "Report-To",
value: JSON.stringify({ "url": reportURI,
@ -9,39 +16,40 @@ function ReportingCSP(reportURI, reportGroup) {
};
return Object.assign(
new CapsCSP(new NetCSP(
`report-uri ${reportURI};`,
`;report-to ${reportGroup};`
)),
REPORT_TO_SUPPORTED ? `;report-to ${reportGroup};`
: `report-uri ${reportURI};`
)),
{
reportURI,
reportGroup,
patchHeaders(responseHeaders, capabilities) {
let header = null;
let hasReportTo = false;
let needsReportTo = REPORT_TO_SUPPORTED;
for (let h of responseHeaders) {
if (this.isMine(h)) {
header = h;
h.value = this.inject(h.value, "");
} else if (h.name === REPORT_TO.name && h.value === REPORT_TO.value) {
hasReportTo = true;
h.value = "";
} else if (needsReportTo &&
h.name === REPORT_TO.name && h.value === REPORT_TO.value) {
needsReportTo = false;
}
}
let blocker = capabilities && this.buildFromCapabilities(capabilities);
if (blocker) {
if (!hasReportTo) {
if (needsReportTo) {
responseHeaders.push(REPORT_TO);
}
if (header) {
header.value = this.inject(header.value, blocker);
header.value = blocker;
} else {
header = this.asHeader(blocker);
responseHeaders.push(header);
}
}
return header;
}
}
);
}
}

View File

@ -1,32 +1,20 @@
"use strict";
class NetCSP extends CSP {
constructor(start, end) {
constructor(start) {
super();
this.start = start;
this.end = end;
}
isMine(header) {
let {name, value} = header;
if (name.toLowerCase() !== CSP.headerName) return false;
let startIdx = value.indexOf(this.start);
return startIdx > -1 && startIdx < value.lastIndexOf(this.end);
return name.toLowerCase() === CSP.headerName && value.startsWith(this.start);
}
inject(headerValue, mine) {
let startIdx = headerValue.indexOf(this.start);
if (startIdx < 0) return `${headerValue};${mine}`;
let endIdx = headerValue.lastIndexOf(this.end);
let retValue = `${headerValue.substring(0, startIdx)}${mine}`;
return endIdx < 0 ? retValue : `${retValue}${headerValue.substring(endIdx + this.end.length + 1)}`;
}
build(...directives) {
return `${this.start}${super.build(...directives)}${this.end}`;
return `${this.start}${super.build(...directives)}`;
}
cleanup(headers) {
}
}