Bug 1329940 - Ignore window.opener for password manager warnings r=baku,jwatt,MattN

MozReview-Commit-ID: KiIR6WEddgO

--HG--
extra : rebase_source : eeae09dad3d10895b9266b249beacdedded3e1a2
This commit is contained in:
Kate McKinley 2017-01-12 16:57:44 -08:00
parent 5a71699e24
commit 88fa83b99b
5 changed files with 59 additions and 5 deletions

View File

@ -2384,7 +2384,7 @@ InitializeLegacyNetscapeObject(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
}
bool
nsGlobalWindow::ComputeIsSecureContext(nsIDocument* aDocument)
nsGlobalWindow::ComputeIsSecureContext(nsIDocument* aDocument, SecureContextFlags aFlags)
{
MOZ_ASSERT(IsOuterWindow());
@ -2394,6 +2394,7 @@ nsGlobalWindow::ComputeIsSecureContext(nsIDocument* aDocument)
}
// Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object
// With some modifications to allow for aFlags.
bool hadNonSecureContextCreator = false;
@ -2419,9 +2420,15 @@ nsGlobalWindow::ComputeIsSecureContext(nsIDocument* aDocument)
MOZ_ASSERT(parentWin ==
nsGlobalWindow::Cast(parentOuterWin->GetCurrentInnerWindow()),
"Creator window mismatch while setting Secure Context state");
hadNonSecureContextCreator = !parentWin->IsSecureContext();
if (aFlags != SecureContextFlags::eIgnoreOpener) {
hadNonSecureContextCreator = !parentWin->IsSecureContext();
} else {
hadNonSecureContextCreator = !parentWin->IsSecureContextIfOpenerIgnored();
}
} else if (mHadOriginalOpener) {
hadNonSecureContextCreator = !mOriginalOpenerWasSecureContext;
if (aFlags != SecureContextFlags::eIgnoreOpener) {
hadNonSecureContextCreator = !mOriginalOpenerWasSecureContext;
}
}
if (hadNonSecureContextCreator) {
@ -2726,6 +2733,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
"Failed to get script global");
newInnerWindow->mIsSecureContextIfOpenerIgnored =
ComputeIsSecureContext(aDocument, SecureContextFlags::eIgnoreOpener);
mCreatingInnerWindow = false;
createdInnerWindow = true;
@ -3867,6 +3876,12 @@ nsPIDOMWindowInner::IsSecureContext() const
return nsGlobalWindow::Cast(this)->IsSecureContext();
}
bool
nsPIDOMWindowInner::IsSecureContextIfOpenerIgnored() const
{
return nsGlobalWindow::Cast(this)->IsSecureContextIfOpenerIgnored();
}
void
nsPIDOMWindowInner::Suspend()
{
@ -13827,6 +13842,14 @@ nsGlobalWindow::IsSecureContext() const
return JS_GetIsSecureContext(js::GetObjectCompartment(GetWrapperPreserveColor()));
}
bool
nsGlobalWindow::IsSecureContextIfOpenerIgnored() const
{
MOZ_RELEASE_ASSERT(IsInnerWindow());
return mIsSecureContextIfOpenerIgnored;
}
already_AddRefed<External>
nsGlobalWindow::GetExternal(ErrorResult& aRv)
{

View File

@ -911,6 +911,7 @@ public:
// https://w3c.github.io/webappsec-secure-contexts/#dom-window-issecurecontext
bool IsSecureContext() const;
bool IsSecureContextIfOpenerIgnored() const;
void GetSidebar(mozilla::dom::OwningExternalOrWindowProxy& aResult,
mozilla::ErrorResult& aRv);
@ -1753,9 +1754,16 @@ private:
void DisconnectEventTargetObjects();
enum class SecureContextFlags {
eDefault,
eIgnoreOpener
};
// Called only on outer windows to compute the value that will be returned by
// IsSecureContext() for the inner window that corresponds to aDocument.
bool ComputeIsSecureContext(nsIDocument* aDocument);
bool ComputeIsSecureContext(nsIDocument* aDocument,
SecureContextFlags aFlags =
SecureContextFlags::eDefault);
// nsPIDOMWindow<T> should be able to see these helper methods.
friend class nsPIDOMWindow<mozIDOMWindowProxy>;
@ -1792,6 +1800,7 @@ protected:
bool mHavePendingClose : 1;
bool mHadOriginalOpener : 1;
bool mOriginalOpenerWasSecureContext : 1;
bool mIsSecureContextIfOpenerIgnored : 1;
bool mIsPopupSpam : 1;
// Indicates whether scripts are allowed to close this window.

View File

@ -851,6 +851,7 @@ public:
* Check whether this window is a secure context.
*/
bool IsSecureContext() const;
bool IsSecureContextIfOpenerIgnored() const;
// Calling suspend should prevent any asynchronous tasks from
// executing javascript for this window. This means setTimeout,

View File

@ -514,3 +514,16 @@ dictionary IdleRequestOptions {
};
callback IdleRequestCallback = void (IdleDeadline deadline);
/**
* Similar to |isSecureContext|, but doesn't pay attention to whether the
* window's opener (if any) is a secure context or not.
*
* WARNING: Do not use this unless you are familiar with the issues that
* taking opener state into account is designed to address (or else you may
* introduce security issues). If in doubt, use |isSecureContext|. In
* particular do not use this to gate access to JavaScript APIs.
*/
partial interface Window {
[ChromeOnly] readonly attribute boolean isSecureContextIfOpenerIgnored;
};

View File

@ -75,7 +75,15 @@ this.InsecurePasswordUtils = {
* @return {boolean} whether the form is secure
*/
isFormSecure(aForm) {
let isSafePage = aForm.ownerDocument.defaultView.isSecureContext;
// We don't want to expose JavaScript APIs in a non-Secure Context even if
// the context is only insecure because the windows has an insecure opener.
// Doing so prevents sites from implementing postMessage workarounds to enable
// an insecure opener to gain access to Secure Context-only APIs. However,
// in the case of form fields such as password fields we don't need to worry
// about whether the opener is secure or not. In fact to flag a password
// field as insecure in such circumstances would unnecessarily confuse our
// users. Hence we use isSecureContextIfOpenerIgnored here.
let isSafePage = aForm.ownerDocument.defaultView.isSecureContextIfOpenerIgnored;
let { isFormSubmitSecure, isFormSubmitHTTP } = this._checkFormSecurity(aForm);
return isSafePage && (isFormSubmitSecure || !isFormSubmitHTTP);