[DOM security] Be more explicit about CSP checks and reports.

This commit is contained in:
Moonchild 2022-09-21 14:08:22 +00:00 • committed by roytam1
commit 95120acbb2
5 changed files with 70 additions and 10 deletions

View file

@ -1721,7 +1721,8 @@ HTMLFormElement::GetActionURL(nsIURI** aActionURL,
// policy - do *not* consult default-src, see: // policy - do *not* consult default-src, see:
// http://www.w3.org/TR/CSP2/#directive-default-src // http://www.w3.org/TR/CSP2/#directive-default-src
rv = csp->Permits(actionURL, nsIContentSecurityPolicy::FORM_ACTION_DIRECTIVE, rv = csp->Permits(actionURL, nsIContentSecurityPolicy::FORM_ACTION_DIRECTIVE,
true, &permitsFormAction); true /*aSpecific */, true /* aSendViolationReports */,
&permitsFormAction);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (!permitsFormAction) { if (!permitsFormAction) {
return NS_ERROR_CSP_FORM_ACTION_VIOLATION; return NS_ERROR_CSP_FORM_ACTION_VIOLATION;

View file

@ -191,7 +191,8 @@ SetBaseURIUsingFirstBaseWithHref(nsIDocument* aDocument, nsIContent* aMustMatch)
// http://www.w3.org/TR/CSP2/#directive-default-src // http://www.w3.org/TR/CSP2/#directive-default-src
bool cspPermitsBaseURI = true; bool cspPermitsBaseURI = true;
rv = csp->Permits(newBaseURI, nsIContentSecurityPolicy::BASE_URI_DIRECTIVE, rv = csp->Permits(newBaseURI, nsIContentSecurityPolicy::BASE_URI_DIRECTIVE,
true, &cspPermitsBaseURI); true /* aSpecific */, true /* aSendViolationReports */,
&cspPermitsBaseURI);
if (NS_FAILED(rv) || !cspPermitsBaseURI) { if (NS_FAILED(rv) || !cspPermitsBaseURI) {
newBaseURI = nullptr; newBaseURI = nullptr;
} }

View file

@ -252,9 +252,6 @@ interface nsIContentSecurityPolicy : nsISerializable
/** /**
* Checks if a specific directive permits loading of a URI. * 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 * @param aURI
* The URI about to be loaded or used. * The URI about to be loaded or used.
* @param aDir * @param aDir
@ -266,11 +263,17 @@ interface nsIContentSecurityPolicy : nsISerializable
* "false" allows CSP to fall back to default-src. This function * "false" allows CSP to fall back to default-src. This function
* behaves the same for both values of canUseDefault when querying * behaves the same for both values of canUseDefault when querying
* directives that don't fall-back. * 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 * @return
* Whether or not the provided URI is allowed by CSP under the given * Whether or not the provided URI is allowed by CSP under the given
* directive. (block the pending operation if false). * 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 * Delegate method called by the service when sub-elements of the protected

View file

@ -1309,6 +1309,7 @@ NS_IMETHODIMP
nsCSPContext::Permits(nsIURI* aURI, nsCSPContext::Permits(nsIURI* aURI,
CSPDirective aDir, CSPDirective aDir,
bool aSpecific, bool aSpecific,
bool aSendViolationReports,
bool* outPermits) bool* outPermits)
{ {
// Can't perform check without aURI // Can't perform check without aURI
@ -1323,13 +1324,13 @@ nsCSPContext::Permits(nsIURI* aURI,
false, // not redirected. false, // not redirected.
false, // not a preload. false, // not a preload.
aSpecific, aSpecific,
true, // send violation reports aSendViolationReports,
true, // send blocked URI in violation reports true, // send blocked URI in violation reports
false); // not parser created false); // not parser created
if (CSPCONTEXTLOGENABLED()) { if (CSPCONTEXTLOGENABLED()) {
CSPCONTEXTLOG(("nsCSPContext::Permits, aUri: %s, aDir: %d, isAllowed: %s", CSPCONTEXTLOG(("nsCSPContext::Permits, aUri: %s, aDir: %s, isAllowed: %s",
aURI->GetSpecOrDefault().get(), aDir, aURI->GetSpecOrDefault().get(), CSP_CSPDirectiveToString(aDir),
*outPermits ? "allow" : "deny")); *outPermits ? "allow" : "deny"));
} }

View file

@ -1018,9 +1018,63 @@ nsHtml5TreeOpExecutor::SetSpeculationBase(const nsAString& aURL)
return; return;
} }
const nsCString& charset = mDocument->GetDocumentCharacterSet(); const nsCString& charset = mDocument->GetDocumentCharacterSet();
DebugOnly<nsresult> rv = NS_NewURI(getter_AddRefs(mSpeculationBaseURI), aURL, nsCOMPtr<nsIURI> newBaseURI;
nsresult rv = NS_NewURI(getter_AddRefs(newBaseURI), aURL,
charset.get(), mDocument->GetDocumentURI()); charset.get(), mDocument->GetDocumentURI());
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to create a URI"); 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<nsIPrincipal> principal = mDocument->NodePrincipal();
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
// Check the document's CSP usually delivered via the CSP header.
nsCOMPtr<nsIContentSecurityPolicy> 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 <meta> tag during speculative
// parsing.
nsCOMPtr<nsIContentSecurityPolicy> 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 void