From 0b653eb76efdf930f5989f2a0cb89991287d0724 Mon Sep 17 00:00:00 2001 From: Carlos Fuentes Date: Tue, 22 Feb 2022 23:16:52 +0100 Subject: [PATCH] feat: add check for trustworthy/non-trustworthy urls --- lib/fetch/util.js | 66 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/lib/fetch/util.js b/lib/fetch/util.js index a1ad951afe4..7ff089122b6 100644 --- a/lib/fetch/util.js +++ b/lib/fetch/util.js @@ -343,20 +343,44 @@ function determineRequestsReferrer (request) { ? referrerOrigin = stripURLForReferrer(referrerSource, true) : temp const areSameOrigin = sameOrigin(request, referrerUrl) + const isNonPotentiallyTrustWorthy = isURLPotentiallyTrustworthy(referrerUrl) && + !isURLPotentiallyTrustworthy(request.url) // NOTE: How to treat step 7? // 8. Execute the switch statements corresponding to the value of policy: switch (policy) { case 'origin': return referrerOrigin case 'unsafe-url': return referrerUrl - // TODO: assess if trustworthy or not - case 'strict-origin': return referrerOrigin + case 'strict-origin': + /** + * 1. If referrerURL is a potentially trustworthy URL and + * request’s current URL is not a potentially trustworthy URL, + * then return no referrer. + * 2. Return referrerOrigin + */ + return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin case 'strict-origin-when-cross-origin': + /** + * 1. If the origin of referrerURL and the origin of request’s current URL are the same, + * then return referrerURL. + * 2. If referrerURL is a potentially trustworthy URL and request’s current URL is not a + * potentially trustworthy URL, then return no referrer. + * 3. Return referrerOrigin + */ + if (areSameOrigin) return referrerOrigin + else return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin + case 'same-origin': return areSameOrigin ? referrerOrigin : 'no-referrer' case 'origin-when-cross-origin': return areSameOrigin ? referrerUrl : referrerOrigin case 'no-referrer-when-downgrade': - return referrerUrl + /** + * 1. If referrerURL is a potentially trustworthy URL and + * request’s current URL is not a potentially trustworthy URL, + * then return no referrer. + * 2. Return referrerOrigin + */ + return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin } function stripURLForReferrer (url, originOnly = false) { @@ -372,8 +396,42 @@ function determineRequestsReferrer (request) { return urlObject.href } +} + +function isURLPotentiallyTrustworthy (url) { + if (!(url instanceof URL)) { + return false + } + + if (url.href === 'about:blank' || url.href === 'about:srcdoc') { + return true + } + + if (url.protocol === 'data:') return true + + return isOriginPotentiallyTrustworthy(url.origin) + + function isOriginPotentiallyTrustworthy(origin) { + if (origin == null || origin === 'null') return false - return 'no-referrer' + let originAsURL + + try { originAsURL = new URL(origin) } catch (e) { return false } + + if (originAsURL.protocol === 'https:' || originAsURL.protocol === 'wss:') { + return true + } + + if (/^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*:)*?:?0*1$/.test(originAsURL.hostname) || + (originAsURL.hostname === 'localhost' || originAsURL.hostname.includes('localhost.')) || + (originAsURL.hostname.endsWith('.localhost'))) { + return true + } + + if (originAsURL.protocol === 'file:') return true + + return false + } } function matchRequestIntegrity (request, bytes) {