From d8979aa9f6040457e3d45ae2d1bb658e2bb93fb1 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Thu, 22 Sep 2022 10:46:25 +0800 Subject: [PATCH] import from UXP: [DOM security] Be more explicit about CSP checks and reports. (95120acb) --- dom/html/HTMLFormElement.cpp | 3 +- dom/html/HTMLSharedElement.cpp | 3 +- .../security/nsIContentSecurityPolicy.idl | 11 ++-- dom/security/nsCSPContext.cpp | 7 ++- parser/html/nsHtml5TreeOpExecutor.cpp | 56 ++++++++++++++++++- 5 files changed, 70 insertions(+), 10 deletions(-) diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index 728ce32aa..7e7c8a581 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -1700,7 +1700,8 @@ HTMLFormElement::GetActionURL(nsIURI** aActionURL, // policy - do *not* consult default-src, see: // http://www.w3.org/TR/CSP2/#directive-default-src rv = csp->Permits(actionURL, nsIContentSecurityPolicy::FORM_ACTION_DIRECTIVE, - true, &permitsFormAction); + true /*aSpecific */, true /* aSendViolationReports */, + &permitsFormAction); NS_ENSURE_SUCCESS(rv, rv); if (!permitsFormAction) { return NS_ERROR_CSP_FORM_ACTION_VIOLATION; diff --git a/dom/html/HTMLSharedElement.cpp b/dom/html/HTMLSharedElement.cpp index a7a10b082..16e6c188d 100644 --- a/dom/html/HTMLSharedElement.cpp +++ b/dom/html/HTMLSharedElement.cpp @@ -192,7 +192,8 @@ SetBaseURIUsingFirstBaseWithHref(nsIDocument* aDocument, nsIContent* aMustMatch) // http://www.w3.org/TR/CSP2/#directive-default-src bool cspPermitsBaseURI = true; rv = csp->Permits(newBaseURI, nsIContentSecurityPolicy::BASE_URI_DIRECTIVE, - true, &cspPermitsBaseURI); + true /* aSpecific */, true /* aSendViolationReports */, + &cspPermitsBaseURI); if (NS_FAILED(rv) || !cspPermitsBaseURI) { newBaseURI = nullptr; } diff --git a/dom/interfaces/security/nsIContentSecurityPolicy.idl b/dom/interfaces/security/nsIContentSecurityPolicy.idl index da4297f33..e76c39c44 100644 --- a/dom/interfaces/security/nsIContentSecurityPolicy.idl +++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl @@ -252,9 +252,6 @@ interface nsIContentSecurityPolicy : nsISerializable /** * Checks if a specific directive permits loading of a URI. * - * NOTE: Calls to this may trigger violation reports when queried, so the - * return value should not be cached. - * * @param aURI * The URI about to be loaded or used. * @param aDir @@ -266,11 +263,17 @@ interface nsIContentSecurityPolicy : nsISerializable * "false" allows CSP to fall back to default-src. This function * behaves the same for both values of canUseDefault when querying * directives that don't fall-back. + * @param aSendViolationReports + * If `true` and the uri is not allowed then trigger violation reports. + * This should be `false` for caching or preloads. * @return * Whether or not the provided URI is allowed by CSP under the given * directive. (block the pending operation if false). */ - boolean permits(in nsIURI aURI, in CSPDirective aDir, in boolean aSpecific); + boolean permits(in nsIURI aURI, + in CSPDirective aDir, + in boolean aSpecific, + in boolean aSendViolationReports); /** * Delegate method called by the service when sub-elements of the protected diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp index 2ab5408cb..a6a2a0d22 100644 --- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -1310,6 +1310,7 @@ NS_IMETHODIMP nsCSPContext::Permits(nsIURI* aURI, CSPDirective aDir, bool aSpecific, + bool aSendViolationReports, bool* outPermits) { // Can't perform check without aURI @@ -1324,13 +1325,13 @@ nsCSPContext::Permits(nsIURI* aURI, false, // not redirected. false, // not a preload. aSpecific, - true, // send violation reports + aSendViolationReports, true, // send blocked URI in violation reports false); // not parser created if (CSPCONTEXTLOGENABLED()) { - CSPCONTEXTLOG(("nsCSPContext::Permits, aUri: %s, aDir: %d, isAllowed: %s", - aURI->GetSpecOrDefault().get(), aDir, + CSPCONTEXTLOG(("nsCSPContext::Permits, aUri: %s, aDir: %s, isAllowed: %s", + aURI->GetSpecOrDefault().get(), CSP_CSPDirectiveToString(aDir), *outPermits ? "allow" : "deny")); } diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index 3502a3e16..5c33879b9 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -1021,9 +1021,63 @@ nsHtml5TreeOpExecutor::SetSpeculationBase(const nsAString& aURL) return; } const nsCString& charset = mDocument->GetDocumentCharacterSet(); - DebugOnly rv = NS_NewURI(getter_AddRefs(mSpeculationBaseURI), aURL, + nsCOMPtr newBaseURI; + nsresult rv = NS_NewURI(getter_AddRefs(newBaseURI), aURL, charset.get(), mDocument->GetDocumentURI()); NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to create a URI"); + if (!newBaseURI) { + return; + } + + if (!CSPService::sCSPEnabled) { + // If CSP is not enabled, just pass back the URI + mSpeculationBaseURI = newBaseURI; + return; + } + + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + nsCOMPtr principal = mDocument->NodePrincipal(); + nsCOMPtr domDoc = do_QueryInterface(mDocument); + + // Check the document's CSP usually delivered via the CSP header. + nsCOMPtr documentCsp; + rv = principal->EnsureCSP(domDoc, getter_AddRefs(documentCsp)); + NS_ENSURE_SUCCESS_VOID(rv); + if (documentCsp) { + // base-uri should not fallback to the default-src and preloads should not + // trigger violation reports. + bool cspPermitsBaseURI = true; + rv = documentCsp->Permits( + newBaseURI, + nsIContentSecurityPolicy::BASE_URI_DIRECTIVE, + true /* aSpecific */, + false /* aSendViolationReports */, + &cspPermitsBaseURI); + if (NS_FAILED(rv) || !cspPermitsBaseURI) { + return; + } + } + + // Also check the CSP discovered from the tag during speculative + // parsing. + nsCOMPtr preloadCsp; + rv = principal->EnsurePreloadCSP(domDoc, getter_AddRefs(preloadCsp)); + NS_ENSURE_SUCCESS_VOID(rv); + if (preloadCsp) { + bool cspPermitsBaseURI = true; + rv = preloadCsp->Permits( + newBaseURI, + nsIContentSecurityPolicy::BASE_URI_DIRECTIVE, + true /* aSpecific */, + false /* aSendViolationReports */, + &cspPermitsBaseURI); + if (NS_FAILED(rv) || !cspPermitsBaseURI) { + return; + } + } + + mSpeculationBaseURI = newBaseURI; } void