Bug 1549754 - Prevent external protocol handlers from being considered insecure. r=ckerschb
authorJonathan Kingston <jkt@mozilla.com>
Fri, 10 May 2019 14:17:40 +0000
changeset 535479 8990b9990220bf229abe7c5f5ec6934802559af2
parent 535478 b7145dad7ce17f1f8f72c8974b7472ffd1c84e17
child 535480 0236578639fa675965fb3c0c65e1e1c6984f28f0
push id2082
push userffxbld-merge
push dateMon, 01 Jul 2019 08:34:18 +0000
treeherdermozilla-release@2fb19d0466d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckerschb
bugs1549754
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1549754 - Prevent external protocol handlers from being considered insecure. r=ckerschb Differential Revision: https://phabricator.services.mozilla.com/D30247
dom/html/HTMLFormElement.cpp
dom/security/nsMixedContentBlocker.cpp
dom/security/nsMixedContentBlocker.h
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -49,16 +49,17 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsNetUtil.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIWebProgress.h"
 #include "nsIDocShell.h"
 #include "nsIPrompt.h"
 #include "nsISecurityUITelemetry.h"
 #include "nsIStringBundle.h"
+#include "nsIProtocolHandler.h"
 
 // radio buttons
 #include "mozilla/dom/HTMLInputElement.h"
 #include "nsIRadioVisitor.h"
 #include "RadioNodeList.h"
 
 #include "nsLayoutUtils.h"
 
@@ -762,35 +763,29 @@ nsresult HTMLFormElement::DoSecureToInse
   if (!principalURI) {
     principalURI = OwnerDoc()->GetDocumentURI();
   }
   bool formIsHTTPS;
   rv = principalURI->SchemeIs("https", &formIsHTTPS);
   if (NS_FAILED(rv)) {
     return rv;
   }
-  bool actionIsHTTPS;
-  rv = aActionURL->SchemeIs("https", &actionIsHTTPS);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  bool actionIsJS;
-  rv = aActionURL->SchemeIs("javascript", &actionIsJS);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
 
-  if (!formIsHTTPS || actionIsHTTPS || actionIsJS) {
+  if (!formIsHTTPS) {
     return NS_OK;
   }
 
   if (nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(aActionURL)) {
     return NS_OK;
   }
 
+  if (nsMixedContentBlocker::URISafeToBeLoadedInSecureContext(aActionURL)) {
+    return NS_OK;
+  }
+
   if (nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(aActionURL)) {
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> window = OwnerDoc()->GetWindow();
   if (!window) {
     return NS_ERROR_FAILURE;
   }
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -559,59 +559,22 @@ nsresult nsMixedContentBlocker::ShouldLo
   // by the innerMost URL.
   nsCOMPtr<nsIURI> innerContentLocation = NS_GetInnermostURI(aContentLocation);
   if (!innerContentLocation) {
     NS_ERROR("Can't get innerURI from aContentLocation");
     *aDecision = REJECT_REQUEST;
     return NS_OK;
   }
 
-  /* Get the scheme of the sub-document resource to be requested. If it is
-   * a safe to load in an https context then mixed content doesn't apply.
-   *
-   * Check Protocol Flags to determine if scheme is safe to load:
-   * URI_DOES_NOT_RETURN_DATA - e.g.
-   *   "mailto"
-   * URI_IS_LOCAL_RESOURCE - e.g.
-   *   "data",
-   *   "resource",
-   *   "moz-icon"
-   * URI_INHERITS_SECURITY_CONTEXT - e.g.
-   *   "javascript"
-   * URI_IS_POTENTIALLY_TRUSTWORTHY - e.g.
-   *   "https",
-   *   "moz-safe-about"
-   *
-   */
-  bool schemeLocal = false;
-  bool schemeNoReturnData = false;
-  bool schemeInherits = false;
-  bool schemeSecure = false;
-  if (NS_FAILED(NS_URIChainHasFlags(innerContentLocation,
-                                    nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
-                                    &schemeLocal)) ||
-      NS_FAILED(NS_URIChainHasFlags(
-          innerContentLocation, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA,
-          &schemeNoReturnData)) ||
-      NS_FAILED(
-          NS_URIChainHasFlags(innerContentLocation,
-                              nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
-                              &schemeInherits)) ||
-      NS_FAILED(NS_URIChainHasFlags(
-          innerContentLocation,
-          nsIProtocolHandler::URI_IS_POTENTIALLY_TRUSTWORTHY, &schemeSecure))) {
-    *aDecision = REJECT_REQUEST;
-    return NS_ERROR_FAILURE;
-  }
   // TYPE_IMAGE redirects are cached based on the original URI, not the final
   // destination and hence cache hits for images may not have the correct
   // innerContentLocation.  Check if the cached hit went through an http
   // redirect, and if it did, we can't treat this as a secure subresource.
   if (!aHadInsecureImageRedirect &&
-      (schemeLocal || schemeNoReturnData || schemeInherits || schemeSecure)) {
+      URISafeToBeLoadedInSecureContext(innerContentLocation)) {
     *aDecision = ACCEPT;
     return NS_OK;
   }
 
   // Since there are cases where aRequestingLocation and aRequestPrincipal are
   // definitely not the owning document, we try to ignore them by extracting the
   // requestingLocation in the following order:
   // 1) from the aRequestingContext, either extracting
@@ -1077,16 +1040,53 @@ nsresult nsMixedContentBlocker::ShouldLo
     // from within ShouldLoad
     nsContentUtils::AddScriptRunner(new nsMixedContentEvent(
         aRequestingContext, classification, rootHasSecureConnection));
     *aDecision = ACCEPT;
     return NS_OK;
   }
 }
 
+bool nsMixedContentBlocker::URISafeToBeLoadedInSecureContext(nsIURI* aURI) {
+  /* Returns a bool if the URI can be loaded as a sub resource safely.
+   *
+   * Check Protocol Flags to determine if scheme is safe to load:
+   * URI_DOES_NOT_RETURN_DATA - e.g.
+   *   "mailto"
+   * URI_IS_LOCAL_RESOURCE - e.g.
+   *   "data",
+   *   "resource",
+   *   "moz-icon"
+   * URI_INHERITS_SECURITY_CONTEXT - e.g.
+   *   "javascript"
+   * URI_IS_POTENTIALLY_TRUSTWORTHY - e.g.
+   *   "https",
+   *   "moz-safe-about"
+   *
+   */
+  bool schemeLocal = false;
+  bool schemeNoReturnData = false;
+  bool schemeInherits = false;
+  bool schemeSecure = false;
+  if (NS_FAILED(NS_URIChainHasFlags(
+          aURI, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, &schemeLocal)) ||
+      NS_FAILED(NS_URIChainHasFlags(
+          aURI, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA,
+          &schemeNoReturnData)) ||
+      NS_FAILED(NS_URIChainHasFlags(
+          aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
+          &schemeInherits)) ||
+      NS_FAILED(NS_URIChainHasFlags(
+          aURI, nsIProtocolHandler::URI_IS_POTENTIALLY_TRUSTWORTHY,
+          &schemeSecure))) {
+    return false;
+  }
+  return (schemeLocal || schemeNoReturnData || schemeInherits || schemeSecure);
+}
+
 NS_IMETHODIMP
 nsMixedContentBlocker::ShouldProcess(nsIURI* aContentLocation,
                                      nsILoadInfo* aLoadInfo,
                                      const nsACString& aMimeGuess,
                                      int16_t* aDecision) {
   if (!aContentLocation) {
     // aContentLocation may be null when a plugin is loading without an
     // associated URI resource
--- a/dom/security/nsMixedContentBlocker.h
+++ b/dom/security/nsMixedContentBlocker.h
@@ -66,16 +66,18 @@ class nsMixedContentBlocker : public nsI
                              nsIURI* aRequestingLocation,
                              nsISupports* aRequestingContext,
                              const nsACString& aMimeGuess,
                              nsIPrincipal* aRequestPrincipal,
                              int16_t* aDecision);
   static void AccumulateMixedContentHSTS(
       nsIURI* aURI, bool aActive, const OriginAttributes& aOriginAttributes);
 
+  static bool URISafeToBeLoadedInSecureContext(nsIURI* aURI);
+
   static bool ShouldUpgradeMixedDisplayContent();
 
   static bool sBlockMixedScript;
   static bool sBlockMixedObjectSubrequest;
   static bool sBlockMixedDisplay;
   static bool sUpgradeMixedDisplay;
 };