This commit is contained in:
gorhill 2017-10-18 15:00:22 -04:00
parent b89dbcce39
commit eb7bdba47f
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
4 changed files with 164 additions and 18 deletions

View File

@ -25,7 +25,12 @@
/******************************************************************************/
vAPI.net = {};
vAPI.net = {
onBeforeRequest: {},
onBeforeMaybeSpuriousCSPReport: {},
onHeadersReceived: {},
nativeCSPReportFiltering: false
};
vAPI.net.registerListeners = function() {
@ -286,6 +291,22 @@ vAPI.net.registerListeners = function() {
);
}
// https://github.com/gorhill/uBlock/issues/3140
this.nativeCSPReportFiltering = validTypes.csp_report;
if (
this.nativeCSPReportFiltering &&
typeof this.onBeforeMaybeSpuriousCSPReport.callback === 'function'
) {
wrApi.onBeforeRequest.addListener(
this.onBeforeMaybeSpuriousCSPReport.callback,
{
urls: [ 'http://*/*', 'https://*/*' ],
types: [ 'csp_report' ]
},
[ 'blocking', 'requestBody' ]
);
}
// Chromium 48 and lower does not support `ping` type.
// Chromium 56 and higher does support `csp_report` stype.
if ( onBeforeSendHeaders ) {

View File

@ -25,7 +25,14 @@
/******************************************************************************/
vAPI.net = {};
vAPI.net = {
onBeforeRequest: {},
onBeforeMaybeSpuriousCSPReport: {},
onHeadersReceived: {},
nativeCSPReportFiltering: true
};
/******************************************************************************/
vAPI.net.registerListeners = function() {
@ -129,20 +136,6 @@ vAPI.net.registerListeners = function() {
return onBeforeRequestClient(details);
};
var onHeadersReceivedClient = this.onHeadersReceived.callback,
onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0),
onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes);
var onHeadersReceived = function(details) {
normalizeRequestDetails(details);
if (
onHeadersReceivedClientTypes.length !== 0 &&
onHeadersReceivedClientTypes.indexOf(details.type) === -1
) {
return;
}
return onHeadersReceivedClient(details);
};
if ( onBeforeRequest ) {
let urls = this.onBeforeRequest.urls || ['<all_urls>'];
let types = this.onBeforeRequest.types || undefined;
@ -165,6 +158,32 @@ vAPI.net.registerListeners = function() {
);
}
// https://github.com/gorhill/uBlock/issues/3140
if ( typeof this.onBeforeMaybeSpuriousCSPReport.callback === 'function' ) {
wrApi.onBeforeRequest.addListener(
this.onBeforeMaybeSpuriousCSPReport.callback,
{
urls: [ 'http://*/*', 'https://*/*' ],
types: [ 'csp_report' ]
},
[ 'blocking', 'requestBody' ]
);
}
var onHeadersReceivedClient = this.onHeadersReceived.callback,
onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0),
onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes);
var onHeadersReceived = function(details) {
normalizeRequestDetails(details);
if (
onHeadersReceivedClientTypes.length !== 0 &&
onHeadersReceivedClientTypes.indexOf(details.type) === -1
) {
return;
}
return onHeadersReceivedClient(details);
};
if ( onHeadersReceived ) {
let urls = this.onHeadersReceived.urls || ['<all_urls>'];
let types = onHeadersReceivedTypes;

View File

@ -589,15 +589,26 @@ PageStore.prototype.filterRequest = function(context) {
var requestType = context.requestType;
if ( requestType === 'csp_report' ) {
// https://github.com/gorhill/uBlock/issues/3140
// Special handling of CSP reports if and only if these can't be filtered
// natively.
if (
requestType === 'csp_report' &&
vAPI.net.nativeCSPReportFiltering !== true
) {
if ( this.internalRedirectionCount !== 0 ) {
if ( µb.logger.isEnabled() ) {
this.logData = { result: 1, source: 'global', raw: 'no-spurious-csp-report' };
this.logData = {
result: 1,
source: 'global',
raw: 'no-spurious-csp-report'
};
}
return 1;
}
}
if ( requestType.endsWith('font') ) {
if ( requestType === 'font' ) {
this.remoteFontCount += 1;

View File

@ -382,6 +382,97 @@ var onBeforeBehindTheSceneRequest = function(details) {
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/3140
var onBeforeMaybeSpuriousCSPReport = function(details) {
var tabId = details.tabId;
// Ignore behind-the-scene requests.
if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
// Lookup the page store associated with this tab id.
var µb = µBlock,
pageStore = µb.pageStoreFromTabId(tabId);
if ( pageStore === null ) { return; }
// If uBO is disabled for the page, it can't possibly causes CSP reports
// to be triggered.
if ( pageStore.getNetFilteringSwitch() === false ) { return; }
// A resource was redirected to a neutered one?
// TODO: mind injected scripts/styles as well.
if ( pageStore.internalRedirectionCount === 0 ) { return; }
var textDecoder = onBeforeMaybeSpuriousCSPReport.textDecoder;
if (
textDecoder === undefined &&
typeof self.TextDecoder === 'function'
) {
textDecoder =
onBeforeMaybeSpuriousCSPReport.textDecoder = new TextDecoder();
}
// Find out whether the CSP report is a potentially spurious CSP report.
// If from this point on we are unable to parse the CSP report data, the
// safest assumption to protect users is to assume the CSP report is
// spurious.
if (
textDecoder !== undefined &&
details.method === 'POST'
) {
var raw = details.requestBody && details.requestBody.raw;
if (
Array.isArray(raw) &&
raw.length !== 0 &&
raw[0] instanceof Object &&
raw[0].bytes instanceof ArrayBuffer
) {
var data;
try {
data = JSON.parse(textDecoder.decode(raw[0].bytes));
} catch (ex) {
}
if ( data instanceof Object ) {
var report = data['csp-report'];
if ( report instanceof Object ) {
var blockedURI = report['blocked-uri'] ||
report['blockedURI'],
sourceFile = report['source-file'] ||
report['sourceFile'];
if (
(typeof blockedURI !== 'string' ||
blockedURI.startsWith('data') === false) &&
(typeof sourceFile !== 'string' ||
sourceFile.startsWith('data') === false)
) {
return;
}
}
}
}
}
// Potentially spurious CSP report.
if ( µb.logger.isEnabled() ) {
var hostname = µb.URI.hostnameFromURI(details.url);
µb.logger.writeOne(
tabId,
'net',
{ result: 1, source: 'global', raw: 'no-spurious-csp-report' },
'csp_report',
details.url,
hostname,
hostname
);
}
return { cancel: true };
};
onBeforeMaybeSpuriousCSPReport.textDecoder = undefined;
/******************************************************************************/
// To handle:
// - inline script tags
// - websockets
@ -647,6 +738,10 @@ vAPI.net.onBeforeRequest = {
callback: onBeforeRequest
};
vAPI.net.onBeforeMaybeSpuriousCSPReport = {
callback: onBeforeMaybeSpuriousCSPReport
};
vAPI.net.onHeadersReceived = {
urls: [
'http://*/*',