Bug 1337246 - Part 2 - Detect local IP addresses to ignore for insecure password warnings. r=MattN
authorJohann Hofmann <jhofmann@mozilla.com>
Mon, 08 May 2017 14:58:53 -0400
changeset 357140 c22ec6ec1d1dc4609ec65ad603f551481be50a5c
parent 357139 bae6dd0500bcc5ba62efcd3dd54b8e525e7aa82b
child 357141 f63b9bbe87b7a6622a446cf2c00a7ef60604341f
push id31783
push usercbook@mozilla.com
push dateTue, 09 May 2017 12:03:48 +0000
treeherdermozilla-central@b0ff0c5c0a35 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1337246
milestone55.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 1337246 - Part 2 - Detect local IP addresses to ignore for insecure password warnings. r=MattN MozReview-Commit-ID: 2IWvOJNTnNB
modules/libpref/init/all.js
toolkit/components/passwordmgr/InsecurePasswordUtils.jsm
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2386,16 +2386,17 @@ pref("security.block_script_with_wrong_m
 // Block images of wrong MIME for XCTO: nosniff.
 pref("security.xcto_nosniff_block_images", false);
 
 // OCSP must-staple
 pref("security.ssl.enable_ocsp_must_staple", true);
 
 // Insecure Form Field Warning
 pref("security.insecure_field_warning.contextual.enabled", false);
+pref("security.insecure_field_warning.ignore_local_ip_address", true);
 
 // Disable pinning checks by default.
 pref("security.cert_pinning.enforcement_level", 0);
 // Do not process hpkp headers rooted by not built in roots by default.
 // This is to prevent accidental pinning from MITM devices and is used
 // for tests.
 pref("security.cert_pinning.process_headers_from_non_builtin_roots", false);
 
--- a/toolkit/components/passwordmgr/InsecurePasswordUtils.jsm
+++ b/toolkit/components/passwordmgr/InsecurePasswordUtils.jsm
@@ -1,26 +1,35 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
+/* ownerGlobal doesn't exist in content privileged windows. */
+/* eslint-disable mozilla/use-ownerGlobal */
+
 this.EXPORTED_SYMBOLS = [ "InsecurePasswordUtils" ];
 
 const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 const STRINGS_URI = "chrome://global/locale/security/security.properties";
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gContentSecurityManager",
                                    "@mozilla.org/contentsecuritymanager;1",
                                    "nsIContentSecurityManager");
 XPCOMUtils.defineLazyServiceGetter(this, "gScriptSecurityManager",
                                    "@mozilla.org/scriptsecuritymanager;1",
                                    "nsIScriptSecurityManager");
+XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
+                                  "resource://gre/modules/LoginHelper.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+  return LoginHelper.createLogger("InsecurePasswordUtils");
+});
 
 /*
  * A module that provides utility functions for form security.
  *
  * Note:
  *  This module uses isSecureContextIfOpenerIgnored instead of isSecureContext.
  *
  *  We don't want to expose JavaScript APIs in a non-Secure Context even if
@@ -84,29 +93,57 @@ this.InsecurePasswordUtils = {
       } else {
         isFormSubmitSecure = true;
       }
     }
 
     return { isFormSubmitHTTP, isFormSubmitSecure };
   },
 
+  _isPrincipalForLocalIPAddress(aPrincipal) {
+    try {
+      let uri = aPrincipal.URI;
+      if (Services.io.hostnameIsLocalIPAddress(uri)) {
+        log.debug("hasInsecureLoginForms: detected local IP address:", uri);
+        return true;
+      }
+    } catch (e) {
+      log.debug("hasInsecureLoginForms: unable to check for local IP address:", e);
+    }
+    return false;
+  },
+
   /**
    * Checks if there are insecure password fields present on the form's document
    * i.e. passwords inside forms with http action, inside iframes with http src,
    * or on insecure web pages.
    *
    * @param {FormLike} aForm A form-like object. @See {LoginFormFactory}
    * @return {boolean} whether the form is secure
    */
   isFormSecure(aForm) {
     // Ignores window.opener, see top level documentation.
-    // ownerGlobal doesn't exist in content privileged windows.
-    // eslint-disable-next-line mozilla/use-ownerGlobal
     let isSafePage = aForm.ownerDocument.defaultView.isSecureContextIfOpenerIgnored;
+
+    // Ignore insecure documents with URLs that are local IP addresses.
+    // This is done because the vast majority of routers and other devices
+    // on the network do not use HTTPS, making this warning show up almost
+    // constantly on local connections, which annoys users and hurts our cause.
+    if (!isSafePage && this._ignoreLocalIPAddress) {
+      let isLocalIP = this._isPrincipalForLocalIPAddress(aForm.rootElement.nodePrincipal);
+      let topWindow = aForm.ownerDocument.defaultView.top;
+      let topIsLocalIP = this._isPrincipalForLocalIPAddress(topWindow.document.nodePrincipal);
+
+      // Only consider the page safe if the top window has a local IP address
+      // and, if this is an iframe, the iframe also has a local IP address.
+      if (isLocalIP && topIsLocalIP) {
+        isSafePage = true;
+      }
+    }
+
     let { isFormSubmitSecure, isFormSubmitHTTP } = this._checkFormSecurity(aForm);
 
     return isSafePage && (isFormSubmitSecure || !isFormSubmitHTTP);
   },
 
   /**
    * Report insecure password fields in a form to the web console to warn developers.
    *
@@ -152,8 +189,11 @@ this.InsecurePasswordUtils = {
       passwordSafety = 4;
     } else {
       passwordSafety = 5;
     }
 
     Services.telemetry.getHistogramById("PWMGR_LOGIN_PAGE_SAFETY").add(passwordSafety);
   },
 };
+
+XPCOMUtils.defineLazyPreferenceGetter(this.InsecurePasswordUtils, "_ignoreLocalIPAddress",
+                                      "security.insecure_field_warning.ignore_local_ip_address", true);