mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 09:07:54 +01:00
Report resources blocked by csp=
option in logger
Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/552
This commit is contained in:
parent
12bdd01595
commit
915c1f1f3c
7 changed files with 178 additions and 90 deletions
|
@ -183,6 +183,10 @@ const µBlock = (function() { // jshint ignore:line
|
|||
epickerEprom: null,
|
||||
|
||||
scriptlets: {},
|
||||
|
||||
cspNoInlineScript: "script-src 'unsafe-eval' * blob: data:",
|
||||
cspNoScripting: 'script-src http: https:',
|
||||
cspNoInlineFont: 'font-src *',
|
||||
};
|
||||
|
||||
})();
|
||||
|
|
|
@ -197,6 +197,72 @@ vAPI.SafeAnimationFrame.prototype = {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/552
|
||||
// Listen and report CSP violations so that blocked resources through CSP
|
||||
// are properly reported in the logger.
|
||||
|
||||
{
|
||||
const events = new Set();
|
||||
let timer;
|
||||
|
||||
const send = function() {
|
||||
vAPI.messaging.send(
|
||||
'scriptlets',
|
||||
{
|
||||
what: 'securityPolicyViolation',
|
||||
type: 'net',
|
||||
docURL: document.location.href,
|
||||
violations: Array.from(events),
|
||||
},
|
||||
response => {
|
||||
if ( response === true ) { return; }
|
||||
stop();
|
||||
}
|
||||
);
|
||||
events.clear();
|
||||
};
|
||||
|
||||
const sendAsync = function() {
|
||||
if ( timer !== undefined ) { return; }
|
||||
timer = self.requestIdleCallback(
|
||||
( ) => { timer = undefined; send(); },
|
||||
{ timeout: 2000 }
|
||||
);
|
||||
};
|
||||
|
||||
const listener = function(ev) {
|
||||
if ( ev.isTrusted !== true ) { return; }
|
||||
if ( ev.disposition !== 'enforce' ) { return; }
|
||||
events.add(JSON.stringify({
|
||||
url: ev.blockedURL || ev.blockedURI,
|
||||
policy: ev.originalPolicy,
|
||||
directive: ev.effectiveDirective || ev.violatedDirective,
|
||||
}));
|
||||
sendAsync();
|
||||
};
|
||||
|
||||
const stop = function() {
|
||||
events.clear();
|
||||
if ( timer !== undefined ) {
|
||||
self.cancelIdleCallback(timer);
|
||||
timer = undefined;
|
||||
}
|
||||
document.removeEventListener('securitypolicyviolation', listener);
|
||||
vAPI.shutdown.remove(stop);
|
||||
};
|
||||
|
||||
document.addEventListener('securitypolicyviolation', listener);
|
||||
vAPI.shutdown.add(stop);
|
||||
|
||||
// We need to call at least once to find out whether we really need to
|
||||
// listen to CSP violations.
|
||||
sendAsync();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.domWatcher = (function() {
|
||||
|
||||
const addedNodeLists = [];
|
||||
|
@ -343,7 +409,7 @@ vAPI.domWatcher = (function() {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.matchesProp = (function() {
|
||||
vAPI.matchesProp = (( ) => {
|
||||
const docElem = document.documentElement;
|
||||
if ( typeof docElem.matches !== 'function' ) {
|
||||
if ( typeof docElem.mozMatchesSelector === 'function' ) {
|
||||
|
|
|
@ -567,11 +567,8 @@ var onMessage = function(request, sender, callback) {
|
|||
if ( µb.canInjectScriptletsNow === false ) {
|
||||
response.scriptlets = µb.scriptletFilteringEngine.retrieve(request);
|
||||
}
|
||||
if ( µb.logger.enabled ) {
|
||||
if ( response.noCosmeticFiltering !== true ) {
|
||||
µb.logCosmeticFilters(tabId, frameId);
|
||||
}
|
||||
µb.logInlineScript(tabId, frameId);
|
||||
if ( µb.logger.enabled && response.noCosmeticFiltering !== true ) {
|
||||
µb.logCosmeticFilters(tabId, frameId);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1362,7 +1359,98 @@ const logCosmeticFilters = function(tabId, details) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
const logCSPViolations = function(pageStore, request) {
|
||||
if ( µb.logger.enabled === false || pageStore === null ) {
|
||||
return false;
|
||||
}
|
||||
if ( request.violations.length === 0 ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const fctxt = µb.filteringContext.duplicate();
|
||||
fctxt.fromTabId(pageStore.tabId)
|
||||
.setRealm('network')
|
||||
.setDocOriginFromURL(request.docURL)
|
||||
.setURL(request.docURL);
|
||||
|
||||
let cspData = pageStore.extraData.get('cspData');
|
||||
if ( cspData === undefined ) {
|
||||
cspData = new Map();
|
||||
|
||||
const policies = [];
|
||||
const logData = [];
|
||||
µb.staticNetFilteringEngine.matchAndFetchData(
|
||||
'csp',
|
||||
request.docURL,
|
||||
policies,
|
||||
logData
|
||||
);
|
||||
for ( let i = 0; i < policies.length; i++ ) {
|
||||
cspData.set(policies[i], logData[i]);
|
||||
}
|
||||
|
||||
fctxt.type = 'inline-script';
|
||||
fctxt.filter = undefined;
|
||||
if ( pageStore.filterRequest(fctxt) === 1 ) {
|
||||
cspData.set(µb.cspNoInlineScript, fctxt.filter);
|
||||
}
|
||||
|
||||
fctxt.type = 'script';
|
||||
fctxt.filter = undefined;
|
||||
if ( pageStore.filterScripting(fctxt, true) === 1 ) {
|
||||
cspData.set(µb.cspNoScripting, fctxt.filter);
|
||||
}
|
||||
|
||||
fctxt.type = 'inline-font';
|
||||
fctxt.filter = undefined;
|
||||
if ( pageStore.filterRequest(fctxt) === 1 ) {
|
||||
cspData.set(µb.cspNoInlineFont, fctxt.filter);
|
||||
}
|
||||
|
||||
if ( cspData.size === 0 ) { return false; }
|
||||
|
||||
pageStore.extraData.set('cspData', cspData);
|
||||
}
|
||||
|
||||
const typeMap = logCSPViolations.policyDirectiveToTypeMap;
|
||||
for ( const json of request.violations ) {
|
||||
const violation = JSON.parse(json);
|
||||
let type = typeMap.get(violation.directive);
|
||||
if ( type === undefined ) { continue; }
|
||||
const logData = cspData.get(violation.policy);
|
||||
if ( logData === undefined ) { continue; }
|
||||
if ( /^[\w.+-]+:\/\//.test(violation.url) === false ) {
|
||||
violation.url = request.docURL;
|
||||
if ( type === 'script' ) { type = 'inline-script'; }
|
||||
else if ( type === 'font' ) { type = 'inline-font'; }
|
||||
}
|
||||
fctxt.setURL(violation.url)
|
||||
.setType(type)
|
||||
.setFilter(logData)
|
||||
.toLogger();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
logCSPViolations.policyDirectiveToTypeMap = new Map([
|
||||
[ 'img-src', 'image' ],
|
||||
[ 'connect-src', 'xmlhttprequest' ],
|
||||
[ 'font-src', 'font' ],
|
||||
[ 'frame-src', 'sub_frame' ],
|
||||
[ 'media-src', 'media' ],
|
||||
[ 'object-src', 'object' ],
|
||||
[ 'script-src', 'script' ],
|
||||
[ 'script-src-attr', 'script' ],
|
||||
[ 'script-src-elem', 'script' ],
|
||||
[ 'style-src', 'stylesheet' ],
|
||||
[ 'style-src-attr', 'stylesheet' ],
|
||||
[ 'style-src-elem', 'stylesheet' ],
|
||||
]);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const onMessage = function(request, sender, callback) {
|
||||
const tabId = sender && sender.tab ? sender.tab.id : 0;
|
||||
const pageStore = µb.pageStoreFromTabId(tabId);
|
||||
|
||||
|
@ -1373,7 +1461,7 @@ var onMessage = function(request, sender, callback) {
|
|||
}
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
let response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'domSurveyTransientReport':
|
||||
|
@ -1411,6 +1499,10 @@ var onMessage = function(request, sender, callback) {
|
|||
logCosmeticFilters(tabId, request);
|
||||
break;
|
||||
|
||||
case 'securityPolicyViolation':
|
||||
response = logCSPViolations(pageStore, request);
|
||||
break;
|
||||
|
||||
case 'temporarilyAllowLargeMediaElement':
|
||||
if ( pageStore !== null ) {
|
||||
pageStore.allowLargeMediaElementsUntil = Date.now() + 2000;
|
||||
|
|
|
@ -221,11 +221,12 @@ const pageStoreJunkyardMax = 10;
|
|||
/******************************************************************************/
|
||||
|
||||
const PageStore = function(tabId, context) {
|
||||
this.init(tabId, context);
|
||||
this.extraData = new Map();
|
||||
this.journal = [];
|
||||
this.journalTimer = null;
|
||||
this.journalLastCommitted = this.journalLastUncommitted = undefined;
|
||||
this.journalLastUncommittedURL = undefined;
|
||||
this.init(tabId, context);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -276,6 +277,7 @@ PageStore.prototype.init = function(tabId, context) {
|
|||
this.largeMediaTimer = null;
|
||||
this.netFilteringCache = NetFilteringResultCache.factory();
|
||||
this.internalRedirectionCount = 0;
|
||||
this.extraData.clear();
|
||||
|
||||
// The current filtering context is cloned because:
|
||||
// - We may be called with or without the current context having been
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2018-present Raymond Hill
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
|
||||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// The purpose is to find out whether the current document make use of
|
||||
// inline script tags, and if so report to the main process for logging
|
||||
// purpose.
|
||||
|
||||
(function() {
|
||||
|
||||
if ( typeof vAPI !== 'object' ) { return; }
|
||||
|
||||
if (
|
||||
document.querySelector('script:not([src])') === null &&
|
||||
document.querySelector('a[href^="javascript:"]') === null &&
|
||||
document.querySelector('[onabort],[onblur],[oncancel],[oncanplay],[oncanplaythrough],[onchange],[onclick],[onclose],[oncontextmenu],[oncuechange],[ondblclick],[ondrag],[ondragend],[ondragenter],[ondragexit],[ondragleave],[ondragover],[ondragstart],[ondrop],[ondurationchange],[onemptied],[onended],[onerror],[onfocus],[oninput],[oninvalid],[onkeydown],[onkeypress],[onkeyup],[onload],[onloadeddata],[onloadedmetadata],[onloadstart],[onmousedown],[onmouseenter],[onmouseleave],[onmousemove],[onmouseout],[onmouseover],[onmouseup],[onwheel],[onpause],[onplay],[onplaying],[onprogress],[onratechange],[onreset],[onresize],[onscroll],[onseeked],[onseeking],[onselect],[onshow],[onstalled],[onsubmit],[onsuspend],[ontimeupdate],[ontoggle],[onvolumechange],[onwaiting],[onafterprint],[onbeforeprint],[onbeforeunload],[onhashchange],[onlanguagechange],[onmessage],[onoffline],[ononline],[onpagehide],[onpageshow],[onrejectionhandled],[onpopstate],[onstorage],[onunhandledrejection],[onunload],[oncopy],[oncut],[onpaste]') === null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
vAPI.messaging.send('scriptlets', {
|
||||
what: 'inlinescriptFound',
|
||||
docURL: window.location.href
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
DO NOT:
|
||||
- Remove the following code
|
||||
- Add code beyond the following code
|
||||
Reason:
|
||||
- https://github.com/gorhill/uBlock/pull/3721
|
||||
- uBO never uses the return value from injected content scripts
|
||||
|
||||
**/
|
||||
|
||||
void 0;
|
||||
|
|
@ -773,7 +773,7 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
|||
const builtinDirectives = [];
|
||||
|
||||
if ( pageStore.filterScripting(fctxt, true) === 1 ) {
|
||||
builtinDirectives.push("script-src http: https:");
|
||||
builtinDirectives.push(µBlock.cspNoScripting);
|
||||
if ( loggerEnabled ) {
|
||||
fctxt.setRealm('network').setType('scripting').toLogger();
|
||||
}
|
||||
|
@ -788,9 +788,9 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
|||
fctxt2.setDocOriginFromURL(fctxt.url);
|
||||
const result = pageStore.filterRequest(fctxt2);
|
||||
if ( result === 1 ) {
|
||||
builtinDirectives.push("script-src 'unsafe-eval' * blob: data:");
|
||||
builtinDirectives.push(µBlock.cspNoInlineScript);
|
||||
}
|
||||
if ( result !== 0 && loggerEnabled ) {
|
||||
if ( result === 2 && loggerEnabled ) {
|
||||
fctxt2.setRealm('network').toLogger();
|
||||
}
|
||||
}
|
||||
|
@ -799,14 +799,14 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
|||
// - Use a CSP to also forbid inline fonts if remote fonts are blocked.
|
||||
fctxt.type = 'inline-font';
|
||||
if ( pageStore.filterRequest(fctxt) === 1 ) {
|
||||
builtinDirectives.push('font-src *');
|
||||
builtinDirectives.push(µBlock.cspNoInlineFont);
|
||||
if ( loggerEnabled ) {
|
||||
fctxt.setRealm('network').toLogger();
|
||||
}
|
||||
}
|
||||
|
||||
if ( builtinDirectives.length !== 0 ) {
|
||||
cspSubsets[0] = builtinDirectives.join('; ');
|
||||
cspSubsets[0] = builtinDirectives.join(', ');
|
||||
}
|
||||
|
||||
// ======== filter-based policies
|
||||
|
|
|
@ -555,14 +555,6 @@ var matchBucket = function(url, hostname, bucket, start) {
|
|||
});
|
||||
};
|
||||
|
||||
µBlock.logInlineScript = function(tabId, frameId) {
|
||||
vAPI.tabs.injectScript(tabId, {
|
||||
frameId: frameId,
|
||||
file: '/js/scriptlets/inlinescript-logger.js',
|
||||
runAt: 'document_end'
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.scriptlets = (function() {
|
||||
|
|
Loading…
Reference in a new issue