Bug 1729640 - P4. Setting high-value permission for sites that are considered is logged in. r=farre,sfoster,tgiles

Sites that match the following heuristic are considered high-value:
1. Sites that have a password stored in the password manager
2. Sites that we detect that users submit a form with a password

This patch adds LoginDetectionService to detect login attempts.
When LoginDetectionService finds a site that matches any of the above
heuristics, it adds the corresponding high-value permission to the
permission manager.

Differential Revision: https://phabricator.services.mozilla.com/D127105
This commit is contained in:
Dimi 2021-11-05 17:11:32 +00:00
parent 1170d5bd99
commit 4744525d0d
8 changed files with 274 additions and 3 deletions

View File

@ -2673,6 +2673,16 @@ BrowserGlue.prototype = {
},
},
// Login detection service is used in fission to identify high value sites.
{
task: () => {
let loginDetection = Cc[
"@mozilla.org/login-detection-service;1"
].createInstance(Ci.nsILoginDetectionService);
loginDetection.init();
},
},
// WebDriver components (Remote Agent and Marionette) need to be
// initialized as very last step.
{

View File

@ -0,0 +1,137 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LoginDetectionService.h"
#include "nsILoginInfo.h"
#include "nsILoginManager.h"
#include "nsIObserver.h"
#include "nsIXULRuntime.h"
#include "nsServiceManagerUtils.h"
#include "nsXULAppAPI.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/dom/ProcessIsolation.h"
namespace mozilla::dom {
static StaticRefPtr<LoginDetectionService> gLoginDetectionService;
namespace {
void OnFissionPrefsChange(const char* aPrefName, void* aData) {
MOZ_ASSERT(gLoginDetectionService);
gLoginDetectionService->MaybeStartMonitoring();
}
} // namespace
NS_IMPL_ISUPPORTS(LoginDetectionService, nsILoginDetectionService,
nsILoginSearchCallback, nsIObserver, nsISupportsWeakReference)
// static
already_AddRefed<LoginDetectionService> LoginDetectionService::GetSingleton() {
if (gLoginDetectionService) {
return do_AddRef(gLoginDetectionService);
}
gLoginDetectionService = new LoginDetectionService();
ClearOnShutdown(&gLoginDetectionService);
return do_AddRef(gLoginDetectionService);
}
LoginDetectionService::~LoginDetectionService() { UnregisterObserver(); }
void LoginDetectionService::MaybeStartMonitoring() {
if (IsIsolateHighValueSiteEnabled()) {
// We want to isolate sites with a saved password, so fetch saved logins
// from the password manager, and then add the 'HighValue' permission.
// Note that we don't monitor whether a login is added or removed after
// logins are fetched. For adding logins, this will be covered by form
// submission detection heuristic. As for removing logins, it doesn't
// provide security benefit just to NOT isolate the removed site. The site
// will not be isolated when its permission expired.
FetchLogins();
if (!mObs) {
mObs = mozilla::services::GetObserverService();
mObs->AddObserver(this, "passwordmgr-form-submission-detected", false);
}
} else {
UnregisterObserver();
}
}
void LoginDetectionService::FetchLogins() {
nsresult rv;
nsCOMPtr<nsILoginManager> loginManager =
do_GetService(NS_LOGINMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(!loginManager)) {
return;
}
Unused << loginManager->GetAllLoginsWithCallbackAsync(this);
}
void LoginDetectionService::UnregisterObserver() {
if (mObs) {
mObs->RemoveObserver(this, "passwordmgr-form-submission-detected");
mObs = nullptr;
}
}
///////////////////////////////////////////////////////////////////////////////
// nsILoginDetectionService implementation
NS_IMETHODIMP LoginDetectionService::Init() {
if (XRE_IsContentProcess()) {
return NS_OK;
}
Preferences::RegisterCallback(OnFissionPrefsChange, "fission.autostart");
Preferences::RegisterCallback(OnFissionPrefsChange,
"fission.webContentIsolationStrategy");
MaybeStartMonitoring();
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
// nsILoginSearchObserver implementation
NS_IMETHODIMP
LoginDetectionService::OnSearchComplete(
const nsTArray<RefPtr<nsILoginInfo>>& aLogins) {
// Add all origins with saved passwords to the permission manager.
for (const auto& login : aLogins) {
nsString origin;
login->GetOrigin(origin);
AddHighValuePermission(NS_ConvertUTF16toUTF8(origin),
mozilla::dom::kHighValueHasSavedLoginPermission);
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
// nsIObserver implementation
NS_IMETHODIMP
LoginDetectionService::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
if ("passwordmgr-form-submission-detected"_ns.Equals(aTopic)) {
nsDependentString origin(aData);
AddHighValuePermission(NS_ConvertUTF16toUTF8(origin),
mozilla::dom::kHighValueIsLoggedInPermission);
}
return NS_OK;
}
} // namespace mozilla::dom

View File

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_LoginDetectionService_h
#define mozilla_dom_LoginDetectionService_h
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsILoginDetectionService.h"
#include "nsILoginManager.h"
#include "nsWeakReference.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
namespace mozilla::dom {
/**
* Detect whether the user is 'possibly' logged in to a site, and add the
* HighValue permission to the permission manager. We say 'possibly' because
* the detection is done in a very loose way. For example, for sites that have
* an associated login stored in the password manager are considered `logged in`
* by the service, which is not always true in terms of whether the users is
* really logged in to the site.
*/
class LoginDetectionService final : public nsILoginDetectionService,
public nsILoginSearchCallback,
public nsIObserver,
public nsSupportsWeakReference {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSILOGINDETECTIONSERVICE
NS_DECL_NSILOGINSEARCHCALLBACK
NS_DECL_NSIOBSERVER
static already_AddRefed<LoginDetectionService> GetSingleton();
void MaybeStartMonitoring();
private:
LoginDetectionService() = default;
virtual ~LoginDetectionService();
// Fetch saved logins from the password manager.
void FetchLogins();
void RegisterObserver();
void UnregisterObserver();
nsCOMPtr<nsIObserverService> mObs;
};
} // namespace mozilla::dom
#endif

View File

@ -955,4 +955,24 @@ void AddHighValuePermission(nsIPrincipal* aResultPrincipal,
nsIPermissionManager::EXPIRE_TIME, expirationTime);
}
void AddHighValuePermission(const nsACString& aOrigin,
const nsACString& aPermissionType) {
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
nsCOMPtr<nsIPrincipal> principal;
nsresult rv =
ssm->CreateContentPrincipalFromOrigin(aOrigin, getter_AddRefs(principal));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
AddHighValuePermission(principal, aPermissionType);
}
bool IsIsolateHighValueSiteEnabled() {
return mozilla::FissionAutostart() &&
WebContentIsolationStrategy(
StaticPrefs::fission_webContentIsolationStrategy()) ==
WebContentIsolationStrategy::IsolateHighValue;
}
} // namespace mozilla::dom

View File

@ -13,9 +13,8 @@
#include "mozilla/dom/RemoteType.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "nsString.h"
class nsIURI;
class nsIPrincipal;
#include "nsIPrincipal.h"
#include "nsIURI.h"
namespace mozilla::dom {
@ -80,6 +79,15 @@ Result<NavigationIsolationOptions, nsresult> IsolationOptionsForNavigation(
void AddHighValuePermission(nsIPrincipal* aResultPrincipal,
const nsACString& aPermissionType);
void AddHighValuePermission(const nsACString& aOrigin,
const nsACString& aPermissionType);
/**
* Returns true when fission is enabled and the
* `fission.webContentIsolationStrategy` pref is set to `IsolateHighValue`.
*/
bool IsIsolateHighValueSiteEnabled();
} // namespace mozilla::dom
#endif

16
dom/ipc/components.conf Normal file
View File

@ -0,0 +1,16 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
Classes = [
{
'cid': '{91fdaa4e-eba4-4ed3-831c-ce05c142822d}',
'contract_ids': ['@mozilla.org/login-detection-service;1'],
'type': 'mozilla::dom::LoginDetectionService',
'singleton': True,
'headers': ['/dom/ipc/LoginDetectionService.h'],
'constructor': 'mozilla::dom::LoginDetectionService::GetSingleton',
},
]

View File

@ -13,10 +13,15 @@ XPIDL_SOURCES += [
"nsIDOMProcessChild.idl",
"nsIDOMProcessParent.idl",
"nsIHangReport.idl",
"nsILoginDetectionService.idl",
]
XPIDL_MODULE = "dom"
XPCOM_MANIFESTS += [
"components.conf",
]
EXTRA_JS_MODULES += [
"ManifestMessagesChild.jsm",
]
@ -53,6 +58,7 @@ EXPORTS.mozilla.dom += [
"FilePickerParent.h",
"InProcessChild.h",
"InProcessParent.h",
"LoginDetectionService.h",
"MaybeDiscarded.h",
"MemoryReportRequest.h",
"NativeThreadId.h",
@ -106,6 +112,7 @@ UNIFIED_SOURCES += [
"DocShellMessageUtils.cpp",
"FilePickerParent.cpp",
"InProcessImpl.cpp",
"LoginDetectionService.cpp",
"MemMapSnapshot.cpp",
"MemoryReportRequest.cpp",
"MMPrinter.cpp",

View File

@ -0,0 +1,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIURI;
[scriptable, uuid(4c3c9a82-722a-4b0b-9c7d-36ef90135537)]
interface nsILoginDetectionService : nsISupports
{
/**
* called to initialize the login detection service.
*/
void init();
};