Bug 1328460 - Don't send priming to IP or non-standard ports r?ckerschb,tanvi draft
authorKate McKinley <kmckinley@mozilla.com>
Wed, 04 Jan 2017 14:36:50 -0800
changeset 457731 851ee9f5748157fe6c556abfb06f5c96dc57ca23
parent 457730 211d8715c9659e67ecde84f112c35c122a0bbe55
child 541573 3246cac05c8bf3ac95f1f533a405b3b8d450800a
push id40874
push userbmo:kmckinley@mozilla.com
push dateMon, 09 Jan 2017 19:01:26 +0000
reviewersckerschb, tanvi
bugs1328460
milestone53.0a1
Bug 1328460 - Don't send priming to IP or non-standard ports r?ckerschb,tanvi MozReview-Commit-ID: GLyLfp8gqYt
dom/security/nsMixedContentBlocker.cpp
dom/security/test/hsts/browser.ini
dom/security/test/hsts/browser_hsts-priming_no-ip-address.js
dom/security/test/hsts/browser_hsts-priming_no-non-standard-ports.js
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -25,19 +25,21 @@
 #include "nsIScriptObjectPrincipal.h"
 #include "nsISecureBrowserUI.h"
 #include "nsIDocumentLoader.h"
 #include "nsIWebNavigation.h"
 #include "nsLoadGroup.h"
 #include "nsIScriptError.h"
 #include "nsIURI.h"
 #include "nsIChannelEventSink.h"
+#include "nsNetUtil.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "mozilla/LoadInfo.h"
 #include "nsISiteSecurityService.h"
+#include "prnetdb.h"
 
 #include "mozilla/Logging.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/ipc/URIUtils.h"
 
 
 using namespace mozilla;
@@ -56,16 +58,43 @@ bool nsMixedContentBlocker::sBlockMixedD
 
 // Do we move HSTS before mixed-content
 bool nsMixedContentBlocker::sUseHSTS = false;
 // Do we send an HSTS priming request
 bool nsMixedContentBlocker::sSendHSTSPriming = false;
 // Default HSTS Priming failure timeout to 7 days, in seconds
 uint32_t nsMixedContentBlocker::sHSTSPrimingCacheTimeout = (60 * 24 * 7);
 
+bool
+IsEligibleForHSTSPriming(nsIURI* aContentLocation) {
+  bool isHttpScheme = false;
+  nsresult rv = aContentLocation->SchemeIs("http", &isHttpScheme);
+  NS_ENSURE_SUCCESS(rv, false);
+  if (!isHttpScheme) {
+    return false;
+  }
+
+  int32_t port = -1;
+  rv = aContentLocation->GetPort(&port);
+  NS_ENSURE_SUCCESS(rv, false);
+  int32_t defaultPort = NS_GetDefaultPort("https");
+
+  if (port != -1 && port != defaultPort) {
+    // HSTS priming requests are only sent if the port is the default port
+    return false;
+  }
+
+  nsAutoCString hostname;
+  rv = aContentLocation->GetHost(hostname);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  PRNetAddr hostAddr;
+  return (PR_StringToNetAddr(hostname.get(), &hostAddr) != PR_SUCCESS);
+}
+
 // Fired at the document that attempted to load mixed content.  The UI could
 // handle this event, for example, by displaying an info bar that offers the
 // choice to reload the page with mixed content permitted.
 class nsMixedContentEvent : public Runnable
 {
 public:
   nsMixedContentEvent(nsISupports *aContext, MixedContentTypes aType, bool aRootHasSecureConnection)
     : mContext(aContext), mType(aType), mRootHasSecureConnection(aRootHasSecureConnection)
@@ -827,17 +856,17 @@ nsMixedContentBlocker::ShouldLoad(bool a
   // Allow load and return early.
   if (!securityUI) {
     *aDecision = nsIContentPolicy::ACCEPT;
     return NS_OK;
   }
   nsresult stateRV = securityUI->GetState(&state);
 
   bool doHSTSPriming = false;
-  if (isHttpScheme) {
+  if (IsEligibleForHSTSPriming(aContentLocation)) {
     bool hsts = false;
     bool cached = false;
     nsCOMPtr<nsISiteSecurityService> sss =
       do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aContentLocation,
         0, &cached, &hsts);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/security/test/hsts/browser.ini
+++ b/dom/security/test/hsts/browser.ini
@@ -12,8 +12,10 @@ support-files =
 [browser_hsts-priming_block_active.js]
 [browser_hsts-priming_hsts_after_mixed.js]
 [browser_hsts-priming_allow_display.js]
 [browser_hsts-priming_block_display.js]
 [browser_hsts-priming_block_active_css.js]
 [browser_hsts-priming_block_active_with_redir_same.js]
 [browser_hsts-priming_no-duplicates.js]
 [browser_hsts-priming_cache-timeout.js]
+[browser_hsts-priming_no-non-standard-ports.js]
+[browser_hsts-priming_no-ip-address.js]
new file mode 100644
--- /dev/null
+++ b/dom/security/test/hsts/browser_hsts-priming_no-ip-address.js
@@ -0,0 +1,30 @@
+/*
+ * Description of the test:
+ *   If the top-level domain sends the STS header but does not have
+ *   includeSubdomains, HSTS priming requests should still be sent to
+ *   subdomains.
+ */
+'use strict';
+
+//jscs:disable
+add_task(function*() {
+  //jscs:enable
+  Observer.add_observers(Services);
+  registerCleanupFunction(do_cleanup);
+
+  // add the top-level server
+  test_servers['localhost-ip'] = {
+    host: '127.0.0.1',
+    response: true,
+    id: 'localhost-ip',
+  };
+  test_settings.block_active.result['localhost-ip'] = 'blocked';
+
+  let which = "block_active";
+
+  SetupPrefTestEnvironment(which);
+
+  yield execute_test("localhost-ip", test_settings[which].mimetype);
+
+  SpecialPowers.popPrefEnv();
+});
new file mode 100644
--- /dev/null
+++ b/dom/security/test/hsts/browser_hsts-priming_no-non-standard-ports.js
@@ -0,0 +1,34 @@
+/*
+ * Description of the test:
+ *   If the top-level domain sends the STS header but does not have
+ *   includeSubdomains, HSTS priming requests should still be sent to
+ *   subdomains.
+ */
+'use strict';
+
+//jscs:disable
+add_task(function*() {
+  //jscs:enable
+  Observer.add_observers(Services);
+  registerCleanupFunction(do_cleanup);
+
+  // add the top-level server
+  test_servers['non-standard-port'] = {
+    host: 'example.com:1234',
+    response: true,
+    id: 'non-standard-port',
+  };
+  test_settings.block_active.result['non-standard-port'] = 'blocked';
+
+  let which = "block_active";
+
+  SetupPrefTestEnvironment(which);
+
+  yield execute_test("non-standard-port", test_settings[which].mimetype);
+
+  yield execute_test("prime-hsts", test_settings[which].mimetype);
+
+  ok("prime-hsts" in test_settings[which_test].priming, "Sent priming request on standard port after non-standard was not primed");
+
+  SpecialPowers.popPrefEnv();
+});