Bug 1425975 P16 Make nsDocShell check for session cookie lifetime policy before allowing service worker intercept. r=asuth

This commit is contained in:
Ben Kelly 2018-01-05 12:10:22 -05:00
parent fd30dd024a
commit 7f0e026bcb
3 changed files with 82 additions and 43 deletions

View File

@ -3455,11 +3455,10 @@ nsDocShell::MaybeCreateInitialClientSource(nsIPrincipal* aPrincipal)
return;
}
// We're done if there is no parent controller. Also, don't inherit
// the controller if we're sandboxed. This matches our behavior in
// ShouldPrepareForIntercept(),
// We're done if there is no parent controller or if this docshell
// is not permitted to control for some reason.
Maybe<ServiceWorkerDescriptor> controller(parentInner->GetController());
if (controller.isNothing() || mSandboxFlags) {
if (controller.isNothing() || !ServiceWorkerAllowedToControlWindow(nullptr)) {
return;
}
@ -15003,6 +15002,54 @@ nsDocShell::CanSetOriginAttributes()
return true;
}
bool
nsDocShell::ServiceWorkerAllowedToControlWindow(nsIURI* aURI)
{
// NOTE: Ideally this method would call one of the
// nsContentUtils::StorageAllowed*() methods to determine if the
// interception is allowed. Unfortunately we cannot safely do this
// before the first window loads in the child process because the
// permission manager might not have all its data yet. Therefore,
// we use this somewhat lame alternate implementation here. Once
// interception is moved to the parent process we should switch
// to calling nsContentUtils::StorageAllowed*(). See bug 1428130.
if (UsePrivateBrowsing() || mSandboxFlags) {
return false;
}
uint32_t cookieBehavior = nsContentUtils::CookiesBehavior();
uint32_t lifetimePolicy = nsContentUtils::CookiesLifetimePolicy();
if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT ||
lifetimePolicy == nsICookieService::ACCEPT_SESSION) {
return false;
}
if (!aURI || cookieBehavior == nsICookieService::BEHAVIOR_ACCEPT) {
return true;
}
nsCOMPtr<nsIDocShellTreeItem> parent;
GetSameTypeParent(getter_AddRefs(parent));
nsCOMPtr<nsPIDOMWindowOuter> parentWindow = parent ? parent->GetWindow()
: nullptr;
if (parentWindow) {
nsresult rv = NS_OK;
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
if (thirdPartyUtil) {
bool isThirdPartyURI = true;
rv = thirdPartyUtil->IsThirdPartyWindow(parentWindow, aURI,
&isThirdPartyURI);
if (NS_SUCCEEDED(rv) && isThirdPartyURI) {
return false;
}
}
}
return true;
}
nsresult
nsDocShell::SetOriginAttributes(const OriginAttributes& aAttrs)
{
@ -15207,27 +15254,11 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNonSubresourceReques
bool* aShouldIntercept)
{
*aShouldIntercept = false;
// No in private browsing
if (UsePrivateBrowsing()) {
return NS_OK;
}
if (mSandboxFlags) {
// If we're sandboxed, don't intercept.
return NS_OK;
}
uint32_t cookieBehavior = nsContentUtils::CookiesBehavior();
if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT) {
// If cookies are disabled, don't intercept.
return NS_OK;
}
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
return NS_OK;
}
// For subresource requests we base our decision solely on the client's
// controller value. Any settings that would have blocked service worker
// access should have been set before the initial navigation created the
// window.
if (!aIsNonSubresourceRequest) {
nsCOMPtr<nsIDocument> doc = GetDocument();
if (!doc) {
@ -15243,27 +15274,19 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNonSubresourceReques
return NS_OK;
}
// If the user has set a cookie policy that restricts cookies, then
// avoid intercepting 3rd party iframes.
if (cookieBehavior != nsICookieService::BEHAVIOR_ACCEPT) {
nsCOMPtr<nsIDocShellTreeItem> parent;
GetSameTypeParent(getter_AddRefs(parent));
nsCOMPtr<nsPIDOMWindowOuter> parentWindow = parent ? parent->GetWindow()
: nullptr;
if (parentWindow) {
nsresult rv = NS_OK;
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
bool isThirdPartyURI = true;
rv = thirdPartyUtil->IsThirdPartyWindow(parentWindow, aURI, &isThirdPartyURI);
if (NS_SUCCEEDED(rv) && isThirdPartyURI) {
return NS_OK;
}
}
// For navigations, first check to see if we are allowed to control a
// window with the given URL.
if (!ServiceWorkerAllowedToControlWindow(aURI)) {
return NS_OK;
}
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
return NS_OK;
}
// We're allowed to control a window, so check with the ServiceWorkerManager
// for a matching service worker.
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateCodebasePrincipal(aURI, mOriginAttributes);
*aShouldIntercept = swm->IsAvailable(principal, aURI);

View File

@ -365,6 +365,17 @@ public:
private:
bool CanSetOriginAttributes();
// Determine if a service worker is allowed to control a window in this
// docshell with the given URL. If there are any reasons it should not,
// this will return false. If true is returned then the window *may* be
// controlled. The caller must still consult either the parent controller
// or the ServiceWorkerManager to determine if a service worker should
// actually control the window.
//
// A nullptr URL is considered to be an about:blank window and will not
// trigger 3rd party iframe checks.
bool ServiceWorkerAllowedToControlWindow(nsIURI* aURI);
public:
const mozilla::OriginAttributes&
GetOriginAttributes()

View File

@ -2937,6 +2937,11 @@ public:
return sCookiesBehavior;
}
static uint32_t CookiesLifetimePolicy()
{
return sCookiesLifetimePolicy;
}
// The order of these entries matters, as we use std::min for total ordering
// of permissions. Private Browsing is considered to be more limiting
// then session scoping