Bug 1509738 - CSP snapshot nonce at load start time. r=baku

--HG--
extra : rebase_source : b532f519b79a3bc14ece0c0ee829edd400149e48
extra : amend_source : d4b8fba240a9d28437ee436b94313fd1602426c4
extra : histedit_source : 6af35eb388f6c23d80d8412533fec02abe2d4cff
This commit is contained in:
Christoph Kerschbaumer 2019-02-13 13:46:50 +01:00
Родитель 610b2a4590
Коммит 7859700e5d
11 изменённых файлов: 112 добавлений и 35 удалений

Просмотреть файл

@ -302,7 +302,8 @@ interface nsIContentSecurityPolicy : nsISerializable
in nsISupports aContext,
in ACString aMimeTypeGuess,
in nsIURI aOriginalURIIfRedirect,
in bool aSendViolationReports);
in bool aSendViolationReports,
in AString aNonce);
%{ C++
// nsIObserver topic to fire when the policy encounters a violation.

Просмотреть файл

@ -311,6 +311,16 @@ nsresult ScriptLoader::CheckContentPolicy(Document* aDocument,
requestingNode, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
contentPolicyType);
// snapshot the nonce at load start time for performing CSP checks
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT) {
nsCOMPtr<Element> element = do_QueryInterface(aContext);
if (element && element->IsHTMLElement()) {
nsAutoString cspNonce;
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
secCheckLoadInfo->SetCspNonce(cspNonce);
}
}
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
nsresult rv = NS_CheckContentLoadPolicy(
aRequest->mURI, secCheckLoadInfo, NS_LossyConvertUTF16toASCII(aType),
@ -1252,6 +1262,17 @@ nsresult ScriptLoader::StartLoad(ScriptLoadRequest* aRequest) {
NS_ENSURE_SUCCESS(rv, rv);
// snapshot the nonce at load start time for performing CSP checks
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT) {
nsCOMPtr<Element> element = do_QueryInterface(context);
if (element && element->IsHTMLElement()) {
nsAutoString cspNonce;
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
loadInfo->SetCspNonce(cspNonce);
}
}
// To avoid decoding issues, the build-id is part of the JSBytecodeMimeType
// constant.
aRequest->mCacheInfo = nullptr;

Просмотреть файл

@ -121,7 +121,8 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
nsISupports* aRequestContext,
const nsACString& aMimeTypeGuess,
nsIURI* aOriginalURIIfRedirect,
bool aSendViolationReports, int16_t* outDecision) {
bool aSendViolationReports, const nsAString& aNonce,
int16_t* outDecision) {
if (CSPCONTEXTLOGENABLED()) {
CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, aContentLocation: %s",
aContentLocation->GetSpecOrDefault().get()));
@ -155,18 +156,8 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
return NS_OK;
}
nsAutoString nonce;
bool parserCreated = false;
if (!isPreload) {
if (aContentType == nsIContentPolicy::TYPE_SCRIPT ||
aContentType == nsIContentPolicy::TYPE_STYLESHEET) {
nsCOMPtr<Element> element = do_QueryInterface(aRequestContext);
if (element && element->IsHTMLElement()) {
// XXXbz What about SVG elements that can have nonce?
element->GetAttribute(NS_LITERAL_STRING("nonce"), nonce);
}
}
nsCOMPtr<nsIScriptElement> script = do_QueryInterface(aRequestContext);
if (script && script->GetParserCreated() != mozilla::dom::NOT_FROM_PARSER) {
parserCreated = true;
@ -177,7 +168,7 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
permitsInternal(dir,
nullptr, // aTriggeringElement
aCSPEventListener, aContentLocation,
aOriginalURIIfRedirect, nonce, isPreload,
aOriginalURIIfRedirect, aNonce, isPreload,
false, // allow fallback to default-src
aSendViolationReports,
true, // send blocked URI in violation reports

Просмотреть файл

@ -172,6 +172,10 @@ CSPService::ShouldLoad(nsIURI *aContentLocation, nsILoadInfo *aLoadInfo,
return NS_OK;
}
nsAutoString cspNonce;
rv = aLoadInfo->GetCspNonce(cspNonce);
NS_ENSURE_SUCCESS(rv, rv);
// 1) Apply speculate CSP for preloads
bool isPreload = nsContentUtils::IsPreloadType(contentType);
@ -186,7 +190,7 @@ CSPService::ShouldLoad(nsIURI *aContentLocation, nsILoadInfo *aLoadInfo,
contentType, cspEventListener, aContentLocation, requestOrigin,
requestContext, aMimeTypeGuess,
nullptr, // no redirect, aOriginal URL is null.
aLoadInfo->GetSendCSPViolationEvents(), aDecision);
aLoadInfo->GetSendCSPViolationEvents(), cspNonce, aDecision);
NS_ENSURE_SUCCESS(rv, rv);
// if the preload policy already denied the load, then there
@ -207,7 +211,8 @@ CSPService::ShouldLoad(nsIURI *aContentLocation, nsILoadInfo *aLoadInfo,
rv = csp->ShouldLoad(contentType, cspEventListener, aContentLocation,
requestOrigin, requestContext, aMimeTypeGuess,
nullptr, // no redirect, aOriginal URL is null.
aLoadInfo->GetSendCSPViolationEvents(), aDecision);
aLoadInfo->GetSendCSPViolationEvents(), cspNonce,
aDecision);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
@ -251,17 +256,6 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
nsIAsyncVerifyRedirectCallback *callback) {
net::nsAsyncRedirectAutoCallback autoCallback(callback);
if (XRE_IsE10sParentProcess()) {
nsCOMPtr<nsIParentChannel> parentChannel;
NS_QueryNotificationCallbacks(oldChannel, parentChannel);
if (parentChannel) {
// This is an IPC'd channel. Don't check it here, because we won't have
// access to the request context; we'll check them in the content
// process instead. Bug 1509738 covers fixing this.
return NS_OK;
}
}
nsCOMPtr<nsIURI> newUri;
nsresult rv = newChannel->GetURI(getter_AddRefs(newUri));
NS_ENSURE_SUCCESS(rv, rv);
@ -303,6 +297,10 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
return rv;
}
nsAutoString cspNonce;
rv = loadInfo->GetCspNonce(cspNonce);
NS_ENSURE_SUCCESS(rv, rv);
bool isPreload = nsContentUtils::IsPreloadType(policyType);
/* On redirect, if the content policy is a preload type, rejecting the preload
@ -330,6 +328,7 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
EmptyCString(), // ACString - MIME guess
originalUri, // Original nsIURI
true, // aSendViolationReports
cspNonce, // nonce
&aDecision);
// if the preload policy already denied the load, then there
@ -356,6 +355,7 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
EmptyCString(), // ACString - MIME guess
originalUri, // Original nsIURI
true, // aSendViolationReports
cspNonce, // nonce
&aDecision);
}

Просмотреть файл

@ -153,7 +153,7 @@ function run_test() {
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
null, // nsICSPEventListener
NetUtil.newURI("http://blocked.test/foo.js"),
null, null, null, null, true);
null, null, null, null, true, null);
});
// test that inline script violations cause a report in report-only policy
@ -206,7 +206,7 @@ function run_test() {
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
null, // nsICSPEventListener
NetUtil.newURI("data:image/png;base64," + base64data),
null, null, null, null, true);
null, null, null, null, true, null);
});
// test that only the uri's scheme is reported for globally unique identifiers
@ -216,7 +216,7 @@ function run_test() {
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SUBDOCUMENT,
null, // nsICSPEventListener
NetUtil.newURI("intent://mymaps.com/maps?um=1&ie=UTF-8&fb=1&sll"),
null, null, null, null, true);
null, null, null, null, true, null);
});
// test fragment removal
@ -227,7 +227,7 @@ function run_test() {
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
null, // nsICSPEventListener
NetUtil.newURI(selfSpec + "#bar"),
null, null, null, null, true);
null, null, null, null, true, null);
});
// test scheme of ftp:
@ -237,6 +237,6 @@ function run_test() {
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
null, // nsICSPEventListener
NetUtil.newURI("ftp://blocked.test/profile.png"),
null, null, null, null, true);
null, null, null, null, true, null);
});
}

Просмотреть файл

@ -457,6 +457,9 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo,
ipcController = controller.ref().ToIPC();
}
nsAutoString cspNonce;
Unused << NS_WARN_IF(NS_FAILED(aLoadInfo->GetCspNonce(cspNonce)));
*aOptionalLoadInfoArgs = LoadInfoArgs(
loadingPrincipalInfo, triggeringPrincipalInfo, principalToInheritInfo,
sandboxedLoadingPrincipalInfo, topLevelPrincipalInfo,
@ -484,7 +487,7 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo,
aLoadInfo->GetIsPreflight(), aLoadInfo->GetLoadTriggeredFromExternal(),
aLoadInfo->GetServiceWorkerTaintingSynthesized(),
aLoadInfo->GetDocumentHasUserInteracted(),
aLoadInfo->GetDocumentHasLoaded(),
aLoadInfo->GetDocumentHasLoaded(), cspNonce,
aLoadInfo->GetIsFromProcessingFrameAttributes());
return NS_OK;
@ -640,7 +643,7 @@ nsresult LoadInfoArgsToLoadInfo(
loadInfoArgs.isPreflight(), loadInfoArgs.loadTriggeredFromExternal(),
loadInfoArgs.serviceWorkerTaintingSynthesized(),
loadInfoArgs.documentHasUserInteracted(),
loadInfoArgs.documentHasLoaded());
loadInfoArgs.documentHasLoaded(), loadInfoArgs.cspNonce());
if (loadInfoArgs.isFromProcessingFrameAttributes()) {
loadInfo->SetIsFromProcessingFrameAttributes();

Просмотреть файл

@ -858,6 +858,16 @@ nsresult Loader::CheckContentPolicy(nsIPrincipal* aLoadingPrincipal,
aLoadingPrincipal, aTriggeringPrincipal, aRequestingNode,
nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK, contentPolicyType);
// snapshot the nonce at load start time for performing CSP checks
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET) {
nsCOMPtr<Element> element = do_QueryInterface(aRequestingNode);
if (element && element->IsHTMLElement()) {
nsAutoString cspNonce;
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
secCheckLoadInfo->SetCspNonce(cspNonce);
}
}
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
nsresult rv = NS_CheckContentLoadPolicy(
aTargetURI, secCheckLoadInfo, NS_LITERAL_CSTRING("text/css"), &shouldLoad,
@ -1310,6 +1320,18 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData,
return rv;
}
// snapshot the nonce at load start time for performing CSP checks
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET) {
nsCOMPtr<Element> element =
do_QueryInterface(aLoadData->mRequestingNode);
if (element && element->IsHTMLElement()) {
nsAutoString cspNonce;
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
loadInfo->SetCspNonce(cspNonce);
}
}
nsCOMPtr<nsIInputStream> stream;
rv = channel->Open(getter_AddRefs(stream));
@ -1438,6 +1460,17 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData,
return rv;
}
// snapshot the nonce at load start time for performing CSP checks
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET) {
nsCOMPtr<Element> element = do_QueryInterface(aLoadData->mRequestingNode);
if (element && element->IsHTMLElement()) {
nsAutoString cspNonce;
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
loadInfo->SetCspNonce(cspNonce);
}
}
if (!aLoadData->ShouldDefer()) {
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
if (cos) {

Просмотреть файл

@ -478,6 +478,7 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
mServiceWorkerTaintingSynthesized(false),
mDocumentHasUserInteracted(rhs.mDocumentHasUserInteracted),
mDocumentHasLoaded(rhs.mDocumentHasLoaded),
mCspNonce(rhs.mCspNonce),
mIsFromProcessingFrameAttributes(rhs.mIsFromProcessingFrameAttributes) {}
LoadInfo::LoadInfo(
@ -510,7 +511,7 @@ LoadInfo::LoadInfo(
const nsTArray<nsCString>& aCorsUnsafeHeaders, bool aForcePreflight,
bool aIsPreflight, bool aLoadTriggeredFromExternal,
bool aServiceWorkerTaintingSynthesized, bool aDocumentHasUserInteracted,
bool aDocumentHasLoaded)
bool aDocumentHasLoaded, const nsAString& aCspNonce)
: mLoadingPrincipal(aLoadingPrincipal),
mTriggeringPrincipal(aTriggeringPrincipal),
mPrincipalToInherit(aPrincipalToInherit),
@ -556,6 +557,7 @@ LoadInfo::LoadInfo(
mServiceWorkerTaintingSynthesized(aServiceWorkerTaintingSynthesized),
mDocumentHasUserInteracted(aDocumentHasUserInteracted),
mDocumentHasLoaded(aDocumentHasLoaded),
mCspNonce(aCspNonce),
mIsFromProcessingFrameAttributes(false) {
// Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal
MOZ_ASSERT(mLoadingPrincipal ||
@ -1254,6 +1256,20 @@ LoadInfo::SetDocumentHasLoaded(bool aDocumentHasLoaded) {
return NS_OK;
}
NS_IMETHODIMP
LoadInfo::GetCspNonce(nsAString& aCspNonce) {
aCspNonce = mCspNonce;
return NS_OK;
}
NS_IMETHODIMP
LoadInfo::SetCspNonce(const nsAString& aCspNonce) {
MOZ_ASSERT(!mInitialSecurityCheckDone,
"setting the nonce is only allowed before any sec checks");
mCspNonce = aCspNonce;
return NS_OK;
}
NS_IMETHODIMP
LoadInfo::GetIsTopLevelLoad(bool* aResult) {
*aResult = mFrameOuterWindowID ? mFrameOuterWindowID == mOuterWindowID

Просмотреть файл

@ -12,6 +12,7 @@
#include "nsIPrincipal.h"
#include "nsIWeakReferenceUtils.h" // for nsWeakPtr
#include "nsIURI.h"
#include "nsString.h"
#include "nsTArray.h"
#include "mozilla/BasePrincipal.h"
@ -121,7 +122,8 @@ class LoadInfo final : public nsILoadInfo {
const nsTArray<nsCString>& aUnsafeHeaders, bool aForcePreflight,
bool aIsPreflight, bool aLoadTriggeredFromExternal,
bool aServiceWorkerTaintingSynthesized,
bool aDocumentHasUserInteracted, bool aDocumentHasLoaded);
bool aDocumentHasUserInteracted, bool aDocumentHasLoaded,
const nsAString& aCspNonce);
LoadInfo(const LoadInfo& rhs);
NS_IMETHOD GetRedirects(JSContext* aCx,
@ -198,6 +200,7 @@ class LoadInfo final : public nsILoadInfo {
bool mServiceWorkerTaintingSynthesized;
bool mDocumentHasUserInteracted;
bool mDocumentHasLoaded;
nsString mCspNonce;
// Is true if this load was triggered by processing the attributes of the
// browsing context container.

Просмотреть файл

@ -1047,6 +1047,14 @@ interface nsILoadInfo : nsISupports
*/
[infallible] attribute boolean documentHasLoaded;
/**
* A snapshot of the nonce at load start time which is used for CSP
* checks and only set for:
* * TYPE_SCRIPT and
* * TYPE_STYLESHEET
*/
attribute AString cspNonce;
/**
* The object in charged to receive CSP violation events. It can be null.
* This attribute will be merged into the CSP object eventually.

Просмотреть файл

@ -109,6 +109,7 @@ struct LoadInfoArgs
bool serviceWorkerTaintingSynthesized;
bool documentHasUserInteracted;
bool documentHasLoaded;
nsString cspNonce;
bool isFromProcessingFrameAttributes;
};