Bug 1653026 - Added HTTPS-Only Mode upgrade info to browser UI state. r=mattwoodrow,necko-reviewers,dragana

Differential Revision: https://phabricator.services.mozilla.com/D86566
This commit is contained in:
julianwels 2020-10-06 00:34:55 +00:00
parent 18d1af1eb5
commit 341416588c
20 changed files with 97 additions and 46 deletions

View File

@ -178,10 +178,9 @@ void CanonicalBrowsingContext::ReplacedBy(
mActiveEntry.swap(aNewContext->mActiveEntry);
}
void CanonicalBrowsingContext::
UpdateSecurityStateForLocationOrMixedContentChange() {
void CanonicalBrowsingContext::UpdateSecurityState() {
if (mSecureBrowserUI) {
mSecureBrowserUI->UpdateForLocationOrMixedContentChange();
mSecureBrowserUI->RecomputeSecurityFlags();
}
}

View File

@ -213,8 +213,8 @@ class CanonicalBrowsingContext final : public BrowsingContext {
// Called when the current URI changes (from an
// nsIWebProgressListener::OnLocationChange event, so that we
// can update our security UI for the new location, or when the
// mixed content state for our current window is changed.
void UpdateSecurityStateForLocationOrMixedContentChange();
// mixed content/https-only state for our current window is changed.
void UpdateSecurityState();
void MaybeAddAsProgressListener(nsIWebProgress* aWebProgress);

View File

@ -334,21 +334,23 @@ void WindowContext::Discard() {
Group()->Unregister(this);
}
void WindowContext::AddMixedContentSecurityState(uint32_t aStateFlags) {
void WindowContext::AddSecurityState(uint32_t aStateFlags) {
MOZ_ASSERT(TopWindowContext() == this);
MOZ_ASSERT((aStateFlags &
(nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
nsIWebProgressListener::STATE_BLOCKED_MIXED_DISPLAY_CONTENT |
nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT)) ==
nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT |
nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED |
nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADE_FAILED)) ==
aStateFlags,
"Invalid flags specified!");
if (XRE_IsParentProcess()) {
Canonical()->AddMixedContentSecurityState(aStateFlags);
Canonical()->AddSecurityState(aStateFlags);
} else {
ContentChild* child = ContentChild::GetSingleton();
child->SendAddMixedContentSecurityState(this, aStateFlags);
child->SendAddSecurityState(this, aStateFlags);
}
}

View File

@ -136,11 +136,10 @@ class WindowContext : public nsISupports, public nsWrapperCache {
static void CreateFromIPC(IPCInitializer&& aInit);
// Add new mixed content security state flags.
// These should be some of the four nsIWebProgressListener
// 'MIXED' state flags, and should only be called on the
// top window context.
void AddMixedContentSecurityState(uint32_t aStateFlags);
// Add new security state flags.
// These should be some of the nsIWebProgressListener 'HTTPS_ONLY_MODE' or
// 'MIXED' state flags, and should only be called on the top window context.
void AddSecurityState(uint32_t aStateFlags);
// This function would be called when its corresponding window is activated
// by user gesture.

View File

@ -5820,9 +5820,7 @@ nsDocShell::OnLocationChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
// changes the current window global, but that happens before this and we
// have a lot of tests that depend on the specific ordering of messages.
if (!(aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT)) {
GetBrowsingContext()
->Canonical()
->UpdateSecurityStateForLocationOrMixedContentChange();
GetBrowsingContext()->Canonical()->UpdateSecurityState();
}
}
return NS_OK;

View File

@ -3167,10 +3167,10 @@ nsresult Document::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
mBlockAllMixedContent = loadInfo->GetBlockAllMixedContent();
mBlockAllMixedContentPreloads = mBlockAllMixedContent;
// HTTPS-Only Mode flags
// The HTTPS_ONLY_EXEMPT flag of the HTTPS-Only state gets propagated to all
// sub-resources and sub-documents.
mHttpsOnlyStatus =
loadInfo->GetHttpsOnlyStatus() & nsILoadInfo::HTTPS_ONLY_EXEMPT;
mHttpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
nsresult rv = InitReferrerInfo(aChannel);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -2688,7 +2688,7 @@ mozilla::ipc::IPCResult BrowserParent::RecvOnLocationChange(
// the current window global, but that happens before this and we have a lot
// of tests that depend on the specific ordering of messages.
if (!(aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT)) {
GetBrowsingContext()->UpdateSecurityStateForLocationOrMixedContentChange();
GetBrowsingContext()->UpdateSecurityState();
}
return IPC_OK();
}

View File

@ -4017,13 +4017,13 @@ bool ContentParent::DeallocPParentToChildStreamParent(
return true;
}
mozilla::ipc::IPCResult ContentParent::RecvAddMixedContentSecurityState(
mozilla::ipc::IPCResult ContentParent::RecvAddSecurityState(
const MaybeDiscarded<WindowContext>& aContext, uint32_t aStateFlags) {
if (aContext.IsNullOrDiscarded()) {
return IPC_OK();
}
aContext.get()->AddMixedContentSecurityState(aStateFlags);
aContext.get()->AddSecurityState(aStateFlags);
return IPC_OK();
}

View File

@ -1103,7 +1103,7 @@ class ContentParent final
const MaybeDiscarded<WindowContext>& aContext,
WindowContext::BaseTransaction&& aTransaction, uint64_t aEpoch);
mozilla::ipc::IPCResult RecvAddMixedContentSecurityState(
mozilla::ipc::IPCResult RecvAddSecurityState(
const MaybeDiscarded<WindowContext>& aContext, uint32_t aStateFlags);
mozilla::ipc::IPCResult RecvFirstIdle();

View File

@ -1055,7 +1055,7 @@ parent:
async OpenNotificationSettings(Principal principal);
async AddMixedContentSecurityState(MaybeDiscardedWindowContext aContext, uint32_t aStateFlags);
async AddSecurityState(MaybeDiscardedWindowContext aContext, uint32_t aStateFlags);
// Request that the ServiceWorkerManager in the parent process create a
// notification "click" or "close" event and dispatch it on the relevant

View File

@ -986,11 +986,11 @@ void WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy) {
};
bool hasMixedDisplay =
mMixedContentSecurityState &
mSecurityState &
(nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
nsIWebProgressListener::STATE_BLOCKED_MIXED_DISPLAY_CONTENT);
bool hasMixedActive =
mMixedContentSecurityState &
mSecurityState &
(nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT);
@ -1102,24 +1102,26 @@ bool WindowGlobalParent::ShouldTrackSiteOriginTelemetry() {
return DocumentPrincipal()->GetIsContentPrincipal();
}
void WindowGlobalParent::AddMixedContentSecurityState(uint32_t aStateFlags) {
void WindowGlobalParent::AddSecurityState(uint32_t aStateFlags) {
MOZ_ASSERT(TopWindowContext() == this);
MOZ_ASSERT((aStateFlags &
(nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
nsIWebProgressListener::STATE_BLOCKED_MIXED_DISPLAY_CONTENT |
nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT)) ==
nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT |
nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED |
nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADE_FAILED)) ==
aStateFlags,
"Invalid flags specified!");
if ((mMixedContentSecurityState & aStateFlags) == aStateFlags) {
if ((mSecurityState & aStateFlags) == aStateFlags) {
return;
}
mMixedContentSecurityState |= aStateFlags;
mSecurityState |= aStateFlags;
if (GetBrowsingContext()->GetCurrentWindowGlobal() == this) {
GetBrowsingContext()->UpdateSecurityStateForLocationOrMixedContentChange();
GetBrowsingContext()->UpdateSecurityState();
}
}

View File

@ -193,8 +193,8 @@ class WindowGlobalParent final : public WindowContext,
uint32_t HttpsOnlyStatus() { return mHttpsOnlyStatus; }
void AddMixedContentSecurityState(uint32_t aStateFlags);
uint32_t GetMixedContentSecurityFlags() { return mMixedContentSecurityState; }
void AddSecurityState(uint32_t aStateFlags);
uint32_t GetSecurityFlags() { return mSecurityState; }
nsITransportSecurityInfo* GetSecurityInfo() { return mSecurityInfo; }
@ -289,7 +289,7 @@ class WindowGlobalParent final : public WindowContext,
// includes the activity log for all of the nested subdocuments as well.
ContentBlockingLog mContentBlockingLog;
uint32_t mMixedContentSecurityState = 0;
uint32_t mSecurityState = 0;
Maybe<ClientInfo> mClientInfo;
// Fields being mirrored from the corresponding document

View File

@ -4,13 +4,14 @@
* 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 "nsHTTPSOnlyUtils.h"
#include "NSSErrorsService.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozpkix/pkixnss.h"
#include "nsCOMPtr.h"
#include "nsHTTPSOnlyStreamListener.h"
#include "nsHTTPSOnlyUtils.h"
#include "nsIChannel.h"
#include "nsIRequest.h"
#include "nsITransportSecurityInfo.h"
@ -23,8 +24,18 @@ NS_IMPL_ISUPPORTS(nsHTTPSOnlyStreamListener, nsIStreamListener,
nsIRequestObserver)
nsHTTPSOnlyStreamListener::nsHTTPSOnlyStreamListener(
nsIStreamListener* aListener)
: mListener(aListener), mCreationStart(mozilla::TimeStamp::Now()) {}
nsIStreamListener* aListener, nsILoadInfo* aLoadInfo)
: mListener(aListener), mCreationStart(mozilla::TimeStamp::Now()) {
RefPtr<mozilla::dom::WindowGlobalParent> wgp =
mozilla::dom::WindowGlobalParent::GetByInnerWindowId(
aLoadInfo->GetInnerWindowID());
// For Top-level document loads (which don't have a requesting window-context)
// we compute these flags once we create the Document in nsSecureBrowserUI.
if (wgp) {
wgp->TopWindowContext()->AddSecurityState(
nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED);
}
}
NS_IMETHODIMP
nsHTTPSOnlyStreamListener::OnDataAvailable(nsIRequest* aRequest,
@ -42,9 +53,28 @@ NS_IMETHODIMP
nsHTTPSOnlyStreamListener::OnStopRequest(nsIRequest* request,
nsresult aStatus) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
// Note: CouldBeHttpsOnlyError also returns true if there was no error
if (nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(channel, aStatus)) {
RecordUpgradeTelemetry(request, aStatus);
LogUpgradeFailure(request, aStatus);
// If the request failed and there is a requesting window-context, set
// HTTPS-Only state flag to indicate a failed upgrade.
// For Top-level document loads (which don't have a requesting
// window-context) we simply check in the UI code whether we landed on the
// HTTPS-Only error page.
if (NS_FAILED(aStatus)) {
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
RefPtr<mozilla::dom::WindowGlobalParent> wgp =
mozilla::dom::WindowGlobalParent::GetByInnerWindowId(
loadInfo->GetInnerWindowID());
if (wgp) {
wgp->TopWindowContext()->AddSecurityState(
nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADE_FAILED);
}
}
}
return mListener->OnStopRequest(request, aStatus);

View File

@ -22,7 +22,8 @@ class nsHTTPSOnlyStreamListener : public nsIStreamListener {
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
explicit nsHTTPSOnlyStreamListener(nsIStreamListener* aListener);
explicit nsHTTPSOnlyStreamListener(nsIStreamListener* aListener,
nsILoadInfo* aLoadInfo);
private:
virtual ~nsHTTPSOnlyStreamListener() = default;

View File

@ -84,7 +84,7 @@ void nsHTTPSOnlyUtils::PotentiallyFireHttpRequestToShortenTimout(
// if it's not a GET method, then there is nothing to do here either.
nsAutoCString method;
Unused << httpChannel->GetRequestMethod(method);
mozilla::Unused << httpChannel->GetRequestMethod(method);
if (!method.EqualsLiteral("GET")) {
return;
}
@ -495,7 +495,7 @@ TestHTTPAnswerRunnable::Notify(nsITimer* aTimer) {
return NS_OK;
}
OriginAttributes attrs = origLoadInfo->GetOriginAttributes();
mozilla::OriginAttributes attrs = origLoadInfo->GetOriginAttributes();
RefPtr<nsIPrincipal> nullPrincipal =
mozilla::NullPrincipal::CreateWithInheritedAttributes(attrs);

View File

@ -898,7 +898,7 @@ nsresult nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
// Notify the top WindowContext of the flags we've computed, and it
// will handle updating any relevant security UI.
topWC->AddMixedContentSecurityState(newState);
topWC->AddSecurityState(newState);
return NS_OK;
}

View File

@ -634,7 +634,7 @@ nsresult nsHttpChannel::OnBeforeConnect() {
if (httpOnlyStatus &
nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_NOT_REGISTERED) {
RefPtr<nsHTTPSOnlyStreamListener> httpsOnlyListener =
new nsHTTPSOnlyStreamListener(mListener);
new nsHTTPSOnlyStreamListener(mListener, mLoadInfo);
mListener = httpsOnlyListener;
httpOnlyStatus ^=

View File

@ -51,7 +51,7 @@ nsSecureBrowserUI::GetState(uint32_t* aState) {
return NS_OK;
}
void nsSecureBrowserUI::UpdateForLocationOrMixedContentChange() {
void nsSecureBrowserUI::RecomputeSecurityFlags() {
// Our BrowsingContext either has a new WindowGlobalParent, or the
// existing one has mutated its security state.
// Recompute our security state and fire notifications to listeners
@ -87,9 +87,17 @@ void nsSecureBrowserUI::UpdateForLocationOrMixedContentChange() {
}
}
// Add the mixed content flags from the window
// Add upgraded-state flags when request has been
// upgraded with HTTPS-Only Mode
if (win) {
mState |= win->GetMixedContentSecurityFlags();
// Check if top-level load has been upgraded
uint32_t httpsOnlyStatus = win->HttpsOnlyStatus();
if (!(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UNINITIALIZED) &&
!(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT)) {
mState |= nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED;
}
// Add the secruity flags from the window
mState |= win->GetSecurityFlags();
}
// If we have loaded mixed content and this is a secure page,

View File

@ -39,7 +39,7 @@ class nsSecureBrowserUI : public nsISecureBrowserUI,
NS_DECL_ISUPPORTS
NS_DECL_NSISECUREBROWSERUI
void UpdateForLocationOrMixedContentChange();
void RecomputeSecurityFlags();
protected:
virtual ~nsSecureBrowserUI() = default;

View File

@ -354,6 +354,18 @@ interface nsIWebProgressListener : nsISupports
const unsigned long STATE_LOADED_SOCIALTRACKING_CONTENT = 0x00020000;
const unsigned long STATE_UNBLOCKED_UNSAFE_CONTENT = 0x00000010;
/**
* Flag for HTTPS-Only Mode upgrades
*
* STATE_HTTPS_ONLY_MODE_UPGRADED
* When a request has been upgraded by HTTPS-Only Mode
*
* STATE_HTTPS_ONLY_MODE_UPGRADE_FAILED
* When an upgraded request failed.
*/
const unsigned long STATE_HTTPS_ONLY_MODE_UPGRADED = 0x00400000;
const unsigned long STATE_HTTPS_ONLY_MODE_UPGRADE_FAILED = 0x00800000;
/**
* Notification indicating the state has changed for one of the requests
* associated with aWebProgress.