Bug 1328695 - Use protocol flags to determine if a URI is potentially trustworthy r=ckerschb, r=dveditz, r=mcmanus, r=bz
authorKate McKinley <kmckinley@mozilla.com>
Thu, 31 May 2018 07:51:42 +0200
changeset 474878 aa4238ab9742f63672f8345acb5fb545e293620e
parent 474851 74279538a616fe15723f71d9181dca590792a983
child 474879 dada0c7fbc6ff85f367f364e842ab7c2895f2fe0
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckerschb, dveditz, mcmanus, bz
bugs1328695
milestone62.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 1328695 - Use protocol flags to determine if a URI is potentially trustworthy r=ckerschb, r=dveditz, r=mcmanus, r=bz Before this change, the trusted URI schemes, based on a string whitelist, were: https, file, resource, app, moz-extension and wss. This change removes "app" from the list (since we don't implement it), and adds "about" to the list (because we control the delivery of that).
docshell/base/nsPingListener.cpp
dom/security/nsContentSecurityManager.cpp
dom/security/nsMixedContentBlocker.cpp
netwerk/base/nsIProtocolHandler.idl
netwerk/protocol/about/nsAboutProtocolHandler.cpp
netwerk/protocol/file/nsFileProtocolHandler.cpp
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/res/ExtensionProtocolHandler.cpp
netwerk/protocol/res/nsResProtocolHandler.h
netwerk/protocol/websocket/BaseWebSocketChannel.cpp
--- a/docshell/base/nsPingListener.cpp
+++ b/docshell/base/nsPingListener.cpp
@@ -157,17 +157,17 @@ SendPing(void* aClosure, nsIContent* aCo
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   nsCOMPtr<nsIScriptSecurityManager> sm =
     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
 
   if (sm && info->referrer) {
     bool referrerIsSecure;
-    uint32_t flags = nsIProtocolHandler::URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
+    uint32_t flags = nsIProtocolHandler::URI_IS_POTENTIALLY_TRUSTWORTHY;
     rv = NS_URIChainHasFlags(info->referrer, flags, &referrerIsSecure);
 
     // Default to sending less data if NS_URIChainHasFlags() fails.
     referrerIsSecure = NS_FAILED(rv) || referrerIsSecure;
 
     bool sameOrigin =
       NS_SUCCEEDED(sm->CheckSameOriginURI(info->referrer, aURI, false));
 
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -885,22 +885,26 @@ nsContentSecurityManager::IsOriginPotent
   NS_WARNING_ASSERTION(!scheme.EqualsLiteral("blob"),
                        "IsOriginPotentiallyTrustworthy ignoring blob scheme");
 
   // According to the specification, the user agent may choose to extend the
   // trust to other, vendor-specific URL schemes. We use this for "resource:",
   // which is technically a substituting protocol handler that is not limited to
   // local resource mapping, but in practice is never mapped remotely as this
   // would violate assumptions a lot of code makes.
-  if (scheme.EqualsLiteral("https") ||
-      scheme.EqualsLiteral("file") ||
-      scheme.EqualsLiteral("resource") ||
-      scheme.EqualsLiteral("app") ||
-      scheme.EqualsLiteral("moz-extension") ||
-      scheme.EqualsLiteral("wss")) {
+  // We use nsIProtocolHandler flags to determine which protocols we consider a priori
+  // authenticated.
+  bool aPrioriAuthenticated = false;
+  if (NS_FAILED(NS_URIChainHasFlags(uri,
+                                    nsIProtocolHandler::URI_IS_POTENTIALLY_TRUSTWORTHY,
+                                    &aPrioriAuthenticated))) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  if (aPrioriAuthenticated) {
     *aIsTrustWorthy = true;
     return NS_OK;
   }
 
   nsAutoCString host;
   rv = uri->GetHost(host);
   if (NS_FAILED(rv)) {
     return NS_OK;
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -592,29 +592,29 @@ nsMixedContentBlocker::ShouldLoad(bool a
   * 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_SAFE_TO_LOAD_IN_SECURE_CONTEXT - e.g.
+  * 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_SAFE_TO_LOAD_IN_SECURE_CONTEXT, &schemeSecure))) {
+      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 &&
--- a/netwerk/base/nsIProtocolHandler.idl
+++ b/netwerk/base/nsIProtocolHandler.idl
@@ -297,20 +297,23 @@ interface nsIProtocolHandler : nsISuppor
 
     /**
      * Channels for this protocol don't need to spin the event loop to handle
      * Open() and reads on the resulting stream.
      */
     const unsigned long URI_SYNC_LOAD_IS_OK = (1<<17);
 
     /**
-     * URI is secure to load in an https page and should not be blocked
-     * by nsMixedContentBlocker
+     * All the origins whose URI has this scheme are considered potentially
+     * trustworthy.
+     * Per the SecureContext spec, https: and wss: should be considered
+     * a priori secure, and implementations may consider other,
+     * implementation-specific URI schemes as secure.
      */
-    const unsigned long URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT = (1<<18);
+    const unsigned long URI_IS_POTENTIALLY_TRUSTWORTHY = (1<<18);
 
     /**
      * This URI may be fetched and the contents are visible to anyone. This is
      * semantically equivalent to the resource being served with all-access CORS
      * headers.
      */
     const unsigned long URI_FETCHABLE_BY_ANYONE = (1 << 19);
 
--- a/netwerk/protocol/about/nsAboutProtocolHandler.cpp
+++ b/netwerk/protocol/about/nsAboutProtocolHandler.cpp
@@ -88,17 +88,17 @@ nsAboutProtocolHandler::GetFlagsForURI(n
     uint32_t aboutModuleFlags = 0;
     rv = aboutMod->GetURIFlags(aURI, &aboutModuleFlags);
     // This should never happen, so pass back the error:
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Secure (https) pages can load safe about pages without becoming
     // mixed content.
     if (aboutModuleFlags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) {
-        *aFlags |= URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
+        *aFlags |= URI_IS_POTENTIALLY_TRUSTWORTHY;
         // about: pages can only be loaded by unprivileged principals
         // if they are marked as LINKABLE
         if (aboutModuleFlags & nsIAboutModule::MAKE_LINKABLE) {
             // Replace URI_DANGEROUS_TO_LOAD with URI_LOADABLE_BY_ANYONE.
             *aFlags &= ~URI_DANGEROUS_TO_LOAD;
             *aFlags |= URI_LOADABLE_BY_ANYONE;
         }
     }
@@ -300,17 +300,17 @@ nsSafeAboutProtocolHandler::GetDefaultPo
 {
     *result = -1;        // no port for moz-safe-about: URLs
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSafeAboutProtocolHandler::GetProtocolFlags(uint32_t *result)
 {
-    *result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE | URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
+    *result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE | URI_IS_POTENTIALLY_TRUSTWORTHY;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSafeAboutProtocolHandler::NewURI(const nsACString &aSpec,
                                    const char *aCharset, // ignore charset info
                                    nsIURI *aBaseURI,
                                    nsIURI **result)
--- a/netwerk/protocol/file/nsFileProtocolHandler.cpp
+++ b/netwerk/protocol/file/nsFileProtocolHandler.cpp
@@ -148,17 +148,18 @@ nsFileProtocolHandler::GetDefaultPort(in
 {
     *result = -1;        // no port for file: URLs
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFileProtocolHandler::GetProtocolFlags(uint32_t *result)
 {
-    *result = URI_NOAUTH | URI_IS_LOCAL_FILE | URI_IS_LOCAL_RESOURCE;
+    *result = URI_NOAUTH | URI_IS_LOCAL_FILE |
+              URI_IS_LOCAL_RESOURCE | URI_IS_POTENTIALLY_TRUSTWORTHY;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFileProtocolHandler::NewURI(const nsACString &spec,
                               const char *charset,
                               nsIURI *aBaseURI,
                               nsIURI **result)
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -2708,17 +2708,17 @@ nsHttpsHandler::GetDefaultPort(int32_t *
 {
     *aPort = NS_HTTPS_DEFAULT_PORT;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHttpsHandler::GetProtocolFlags(uint32_t *aProtocolFlags)
 {
-    *aProtocolFlags = NS_HTTP_PROTOCOL_FLAGS | URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
+    *aProtocolFlags = NS_HTTP_PROTOCOL_FLAGS | URI_IS_POTENTIALLY_TRUSTWORTHY;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHttpsHandler::NewURI(const nsACString &aSpec,
                        const char *aOriginCharset,
                        nsIURI *aBaseURI,
                        nsIURI **_retval)
--- a/netwerk/protocol/res/ExtensionProtocolHandler.cpp
+++ b/netwerk/protocol/res/ExtensionProtocolHandler.cpp
@@ -370,17 +370,19 @@ ExtensionProtocolHandler::GetFlagsForURI
   // subset are web-accessible (and cross-origin fetchable). Check that whitelist.
   bool loadableByAnyone = false;
 
   URLInfo url(aURI);
   if (auto* policy = EPS().GetByURL(url)) {
     loadableByAnyone = policy->IsPathWebAccessible(url.FilePath());
   }
 
-  *aFlags = URI_STD | URI_IS_LOCAL_RESOURCE | (loadableByAnyone ? (URI_LOADABLE_BY_ANYONE | URI_FETCHABLE_BY_ANYONE) : URI_DANGEROUS_TO_LOAD);
+  *aFlags = URI_STD | URI_IS_LOCAL_RESOURCE | URI_IS_POTENTIALLY_TRUSTWORTHY |
+    (loadableByAnyone ? (URI_LOADABLE_BY_ANYONE |
+                         URI_FETCHABLE_BY_ANYONE) : URI_DANGEROUS_TO_LOAD);
   return NS_OK;
 }
 
 bool
 ExtensionProtocolHandler::ResolveSpecialCases(const nsACString& aHost,
                                               const nsACString& aPath,
                                               const nsACString& aPathname,
                                               nsACString& aResult)
--- a/netwerk/protocol/res/nsResProtocolHandler.h
+++ b/netwerk/protocol/res/nsResProtocolHandler.h
@@ -22,17 +22,20 @@ class nsResProtocolHandler final : publi
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIRESPROTOCOLHANDLER
 
     NS_FORWARD_NSIPROTOCOLHANDLER(mozilla::net::SubstitutingProtocolHandler::)
 
     nsResProtocolHandler()
-      : mozilla::net::SubstitutingProtocolHandler("resource", URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE,
+      : mozilla::net::SubstitutingProtocolHandler("resource", URI_STD |
+                                                  URI_IS_UI_RESOURCE |
+                                                  URI_IS_LOCAL_RESOURCE |
+                                                  URI_IS_POTENTIALLY_TRUSTWORTHY,
                                                   /* aEnforceFileOrJar = */ false)
     {}
 
     MOZ_MUST_USE nsresult Init();
 
     NS_IMETHOD SetSubstitution(const nsACString& aRoot, nsIURI* aBaseURI) override;
     NS_IMETHOD SetSubstitutionWithFlags(const nsACString& aRoot, nsIURI* aBaseURI, uint32_t aFlags) override;
 
--- a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
@@ -285,16 +285,19 @@ BaseWebSocketChannel::GetDefaultPort(int
 
 NS_IMETHODIMP
 BaseWebSocketChannel::GetProtocolFlags(uint32_t *aProtocolFlags)
 {
   LOG(("BaseWebSocketChannel::GetProtocolFlags() %p\n", this));
 
   *aProtocolFlags = URI_NORELATIVE | URI_NON_PERSISTABLE | ALLOWS_PROXY |
       ALLOWS_PROXY_HTTP | URI_DOES_NOT_RETURN_DATA | URI_DANGEROUS_TO_LOAD;
+  if (mEncrypted) {
+    *aProtocolFlags |= URI_IS_POTENTIALLY_TRUSTWORTHY;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BaseWebSocketChannel::NewURI(const nsACString & aSpec, const char *aOriginCharset,
                              nsIURI *aBaseURI, nsIURI **_retval)
 {
   LOG(("BaseWebSocketChannel::NewURI() %p\n", this));