Bug 1555050: Always (if non null) set any CSP as cspToInherit on the loadinfo of new document load. Update documentation for GetCSP, GetPreloadCSP() and GetCSPToInherit and update two callsites which called GetCSP instead of GetCSPToInherit. r=bzbarsky

Differential Revision: https://phabricator.services.mozilla.com/D33499

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Christoph Kerschbaumer 2019-06-06 20:19:56 +00:00
Родитель 3997970a6d
Коммит 242bf62249
11 изменённых файлов: 92 добавлений и 58 удалений

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

@ -6937,7 +6937,7 @@ nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
LoadURIOptions loadURIOptions;
loadURIOptions.mTriggeringPrincipal = triggeringPrincipal;
loadURIOptions.mCsp = loadInfo->GetCsp();
loadURIOptions.mCsp = loadInfo->GetCspToInherit();
loadURIOptions.mPostData = newPostData;
return LoadURI(newSpecW, loadURIOptions);
}
@ -10061,16 +10061,16 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
}
}
if (CSP_ShouldResponseInheritCSP(channel)) {
// If the new load needs to inherit the CSP, temporarily store the CSP
// on the loadinfo, and transfer it to the new Document within
// Document::InitCSP(). Please create an actual copy of the CSP (do not
// share the same reference) otherwise a Meta CSP of an opaque origin
// will incorrectly be propagated to the embedding document.
RefPtr<nsCSPContext> cspToInherit = new nsCSPContext();
cspToInherit->InitFromOther(static_cast<nsCSPContext*>(csp.get()));
loadInfo->SetCSPToInherit(cspToInherit);
}
// For document loads we store the CSP that potentially needs to
// be inherited by the new document, e.g. in case we are loading
// an opaque origin like a data: URI. The actual inheritance
// check happens within Document::InitCSP().
// Please create an actual copy of the CSP (do not share the same
// reference) otherwise a Meta CSP of an opaque origin will
// incorrectly be propagated to the embedding document.
RefPtr<nsCSPContext> cspToInherit = new nsCSPContext();
cspToInherit->InitFromOther(static_cast<nsCSPContext*>(csp.get()));
loadInfo->SetCSPToInherit(cspToInherit);
}
nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
@ -11471,7 +11471,7 @@ nsresult nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
triggeringPrincipal = loadInfo->TriggeringPrincipal();
}
if (!csp) {
csp = static_cast<net::LoadInfo*>(loadInfo.get())->GetCSPToInherit();
csp = loadInfo->GetCspToInherit();
}
loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));

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

@ -2951,12 +2951,15 @@ nsresult Document::InitCSP(nsIChannel* aChannel) {
MOZ_ASSERT(!mCSP, "where did mCSP get set if not here?");
// If there is a CSP that needs to be inherited either from the
// embedding doc or from the opening doc, then we query it here
// from the loadinfo because the docshell temporarily stored it
// on the loadinfo so we can set it here.
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
mCSP = static_cast<net::LoadInfo*>(loadInfo.get())->GetCSPToInherit();
// If there is a CSP that needs to be inherited from whatever
// global is considered the client of the document fetch then
// we query it here from the loadinfo in case the newly created
// document needs to inherit the CSP. See:
// https://w3c.github.io/webappsec-csp/#initialize-document-csp
if (CSP_ShouldResponseInheritCSP(aChannel)) {
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
mCSP = loadInfo->GetCspToInherit();
}
// If there is no CSP to inherit, then we create a new CSP here so
// that history entries always have the right reference in case a

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

@ -9505,7 +9505,7 @@ bool nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel) {
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
nsCOMPtr<nsIPrincipal> triggeringPrincipal = loadInfo->TriggeringPrincipal();
nsCOMPtr<nsIContentSecurityPolicy> csp = loadInfo->GetCsp();
nsCOMPtr<nsIContentSecurityPolicy> csp = loadInfo->GetCspToInherit();
// Get the channel's load flags, and use them to generate nsIWebNavigation
// load flags. We want to make sure to propagate the refresh and cache busting

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

@ -161,8 +161,7 @@ nsresult nsJSThunk::EvaluateScript(
// CSP check: javascript: URIs disabled unless "inline" scripts are
// allowed. Here we use the CSP of the thing that started the load,
// which is the CSPToInherit of the loadInfo.
nsCOMPtr<nsIContentSecurityPolicy> csp =
static_cast<mozilla::net::LoadInfo*>(loadInfo.get())->GetCSPToInherit();
nsCOMPtr<nsIContentSecurityPolicy> csp = loadInfo->GetCspToInherit();
if (csp) {
bool allowsInlineScript = true;
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,

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

@ -1702,27 +1702,8 @@ nsresult ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
return rv;
}
nsCOMPtr<nsIURI> uri;
rv = mInfo->Principal()->GetURI(getter_AddRefs(uri));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(!uri)) {
return NS_ERROR_FAILURE;
}
// Create a pristine codebase principal to avoid any possibility of inheriting
// CSP values. The principal on the registration may be polluted with CSP
// from the registering page or other places the principal is passed. If
// bug 965637 is ever fixed this can be removed.
info.mPrincipal =
BasePrincipal::CreateCodebasePrincipal(uri, mInfo->GetOriginAttributes());
if (NS_WARN_IF(!info.mPrincipal)) {
return NS_ERROR_FAILURE;
}
info.mPrincipal = mInfo->Principal();
info.mLoadingPrincipal = info.mPrincipal;
// StoragePrincipal for ServiceWorkers is equal to mPrincipal because, at the
// moment, ServiceWorkers are not exposed in partitioned contexts.
info.mStoragePrincipal = info.mPrincipal;

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

@ -237,6 +237,8 @@ nsresult WorkerLoadInfo::SetPrincipalsAndCSPFromChannel(nsIChannel* aChannel) {
getter_AddRefs(loadGroup));
NS_ENSURE_SUCCESS(rv, rv);
// Workers themselves can have their own CSP - Workers of an opaque origin
// however inherit the CSP of the document that spawned the worker.
nsCOMPtr<nsIContentSecurityPolicy> csp;
if (CSP_ShouldResponseInheritCSP(aChannel)) {
nsCOMPtr<nsILoadInfo> loadinfo = aChannel->LoadInfo();

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

@ -547,7 +547,7 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo,
Maybe<CSPInfo> maybeCspToInheritInfo;
nsCOMPtr<nsIContentSecurityPolicy> cspToInherit =
static_cast<net::LoadInfo*>(aLoadInfo)->GetCSPToInherit();
aLoadInfo->GetCspToInherit();
if (cspToInherit) {
CSPInfo cspToInheritInfo;
Unused << NS_WARN_IF(

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

@ -1484,5 +1484,10 @@ already_AddRefed<nsIContentSecurityPolicy> LoadInfo::GetPreloadCsp() {
return preloadCSP.forget();
}
already_AddRefed<nsIContentSecurityPolicy> LoadInfo::GetCspToInherit() {
nsCOMPtr<nsIContentSecurityPolicy> cspToInherit = mCspToInherit;
return cspToInherit.forget();
}
} // namespace net
} // namespace mozilla

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

@ -91,21 +91,30 @@ class LoadInfo final : public nsILoadInfo {
void SetIsFromProcessingFrameAttributes();
// Hands off from the cspToInherit functionality!
// The only place that knows that a new document load needs to inherit the
// CSP is the docshell. At that point neither the document nor the client
// are available yet. Since we need a way to transfer the CSP from the
// docshell to the document, we temporarily store the CSP that needs to
// be inherited within the Loadinfo. In other words, those two functions
// build the bridge to transfer the CSP from the docshell into the doc.
//
// For navigations, GetCSPToInherit returns what the spec calls the
// "request's client's global object's CSP list", or more precisely
// a snapshot of it taken when the navigation starts. For navigations
// that need to inherit their CSP, this is the right CSP to use for
// the new document. We need a way to transfer the CSP from the
// docshell (where the navigation starts) to the point where the new
// document is created and decides whether to inherit its CSP, and
// this is the mechanism we use for that.
//
// For example:
// A document with a CSP triggers a new top-level data: URI load.
// We pass the CSP of the document that triggered the load all the
// way to docshell. Within docshell we call SetCSPToInherit() on the
// loadinfo. Within Document::InitCSP() we check if the newly created
// document needs to inherit the CSP. If so, we call GetCSPToInherit()
// and set the inherited CSP as the CSP for the new document. Please
// note that any additonal Meta CSP in that document will be merged
// into that CSP. Any subresource loads within that document
// subesquently will receive the correct CSP by querying
// loadinfo->GetCSP() from that point on.
void SetCSPToInherit(nsIContentSecurityPolicy* aCspToInherit) {
mCspToInherit = aCspToInherit;
}
// Certain schemes need to inherit the CSP. If needed, we temporarily
// store the CSP from the embedding/opening document here which then
// gets propagated to the new doc within Document::InitCSP(). This
// member is only ever non-null if the new doc actually needs to
// inherit the CSP from the embedding/opening document.
nsIContentSecurityPolicy* GetCSPToInherit() { return mCspToInherit; }
private:
// private constructor that is only allowed to be called from within

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

@ -1027,11 +1027,46 @@ interface nsILoadInfo : nsISupports
PerformanceStoragePtr GetPerformanceStorage();
/**
* Query the CSP (or Preload CSP for preloads) which should be
* enforced for the channel this loadinfo belongs to.
* Returns the CSP (or Preload CSP for preloads) which should be enforced
* when fetching the resource this loadinfo belongs to.
*
* a) Non-navigations:
* For non-navigation loads, GetCSP() returns what the spec refers to as the
* "request's client's global object's CSP list". In practice, if this is the
* loadinfo of a subresource load (e.g an image load), then GetCSP() or
* GetPreloadCSP() returns the CSP of the document which embeds the image.
* The returned CSP includes any policy delivered through the HTTP header or
* also through the meta tag (modulo the difference for preloads, e.g. image
* preloads have to query GetPreloadCsp() because at the time of preloading
* we are not entirely sure if the Meta CSP will be applied to the document
* in the end or not). Please note that GetCSPToInherit() called on a
* loadinfo for any non-navigation always returns null.
*
* b) Navigations:
* * Top-level loads:
* For top-level loads (navigations) GetCSP() will return null, unless
* the navigation is started by a WebExtension, in which case it will
* return the CSP of the webextension, if any.
* If you need to query the CSP that potentially should apply to the
* new top-level load, you have to query GetCspToInherit(), which is
* the CSP of the request's client's global object, just like GetCsp()
* is for non-navigation requests.
*
* * Iframe-loads:
* For iframe-loads (navigations) GetCSP() will return the CSP of the
* parent document, unless the navigation is started by a WebExtension,
* in which case it will return the CSP of the webextension, if any.
*
* If you need to query the CSP that should potentially be inherited
* into the new document, you have to query GetCSPToInherit().
*
* TODO Bug 1557114:
* After evaluating what CSP to use for frame navigations we should
* update the above documentation to match the outcome of Bug 1557114.
*/
[notxpcom,nostdcall] CSPRef GetCsp();
[notxpcom,nostdcall] CSPRef GetPreloadCsp();
[notxpcom,nostdcall] CSPRef GetCspToInherit();
/**
* The service worker and fetch specifications require returning the

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

@ -73,8 +73,8 @@ interface nsIWebBrowserChrome3 : nsIWebBrowserChrome2
* @param aDocShell
* The docshell performing the load.
* @param aCsp
* The CSP to be used for that load. That is the CSP that e.g. upgrades
* the load to HTTPS in case upgrade-insecure-requests is set.
* The CSP to be used for reloading the top-level load. That is the CSP
* of the document that initially triggered the new document load.
*/
bool reloadInFreshProcess(in nsIDocShell aDocShell,
in nsIURI aURI,