зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1217766 - All PDFs trigger the insecure password warning. r=MattN,bz
--HG-- extra : commitid : 1aP0he1jDxh extra : rebase_source : 49375a644ff345fe479b060945f6fe61efe52df7
This commit is contained in:
Родитель
adef18c336
Коммит
3ae375bf1c
|
@ -518,8 +518,14 @@ nsContentSecurityManager::IsURIPotentiallyTrustworthy(nsIURI* aURI, bool* aIsTru
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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") ||
|
if (scheme.EqualsLiteral("https") ||
|
||||||
scheme.EqualsLiteral("file") ||
|
scheme.EqualsLiteral("file") ||
|
||||||
|
scheme.EqualsLiteral("resource") ||
|
||||||
scheme.EqualsLiteral("app") ||
|
scheme.EqualsLiteral("app") ||
|
||||||
scheme.EqualsLiteral("wss")) {
|
scheme.EqualsLiteral("wss")) {
|
||||||
*aIsTrustWorthy = true;
|
*aIsTrustWorthy = true;
|
||||||
|
|
|
@ -22,6 +22,7 @@ add_task(function* test_isURIPotentiallyTrustworthy() {
|
||||||
["http://localhost/", true],
|
["http://localhost/", true],
|
||||||
["http://127.0.0.1/", true],
|
["http://127.0.0.1/", true],
|
||||||
["file:///", true],
|
["file:///", true],
|
||||||
|
["resource:///", true],
|
||||||
["about:config", false],
|
["about:config", false],
|
||||||
["urn:generic", false],
|
["urn:generic", false],
|
||||||
]) {
|
]) {
|
||||||
|
|
|
@ -62,12 +62,11 @@ this.InsecurePasswordUtils = {
|
||||||
* inside https).
|
* inside https).
|
||||||
*/
|
*/
|
||||||
_checkForInsecureNestedDocuments : function(domDoc) {
|
_checkForInsecureNestedDocuments : function(domDoc) {
|
||||||
let uri = domDoc.documentURIObject;
|
|
||||||
if (domDoc.defaultView == domDoc.defaultView.parent) {
|
if (domDoc.defaultView == domDoc.defaultView.parent) {
|
||||||
// We are at the top, nothing to check here
|
// We are at the top, nothing to check here
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!LoginManagerContent.checkIfURIisSecure(uri)) {
|
if (!LoginManagerContent.isDocumentSecure(domDoc)) {
|
||||||
// We are insecure
|
// We are insecure
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -84,8 +83,8 @@ this.InsecurePasswordUtils = {
|
||||||
*/
|
*/
|
||||||
checkForInsecurePasswords : function (aForm) {
|
checkForInsecurePasswords : function (aForm) {
|
||||||
var domDoc = aForm.ownerDocument;
|
var domDoc = aForm.ownerDocument;
|
||||||
let pageURI = domDoc.defaultView.top.document.documentURIObject;
|
let topDocument = domDoc.defaultView.top.document;
|
||||||
let isSafePage = LoginManagerContent.checkIfURIisSecure(pageURI);
|
let isSafePage = LoginManagerContent.isDocumentSecure(topDocument);
|
||||||
|
|
||||||
if (!isSafePage) {
|
if (!isSafePage) {
|
||||||
this._sendWebConsoleMessage("InsecurePasswordsPresentOnPage", domDoc);
|
this._sendWebConsoleMessage("InsecurePasswordsPresentOnPage", domDoc);
|
||||||
|
|
|
@ -25,6 +25,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
|
||||||
XPCOMUtils.defineLazyServiceGetter(this, "gContentSecurityManager",
|
XPCOMUtils.defineLazyServiceGetter(this, "gContentSecurityManager",
|
||||||
"@mozilla.org/contentsecuritymanager;1",
|
"@mozilla.org/contentsecuritymanager;1",
|
||||||
"nsIContentSecurityManager");
|
"nsIContentSecurityManager");
|
||||||
|
XPCOMUtils.defineLazyServiceGetter(this, "gNetUtil",
|
||||||
|
"@mozilla.org/network/util;1",
|
||||||
|
"nsINetUtil");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
||||||
let logger = LoginHelper.createLogger("LoginManagerContent");
|
let logger = LoginHelper.createLogger("LoginManagerContent");
|
||||||
|
@ -416,9 +419,7 @@ var LoginManagerContent = {
|
||||||
// Returns true if this window or any subframes have insecure login forms.
|
// Returns true if this window or any subframes have insecure login forms.
|
||||||
let hasInsecureLoginForms = (thisWindow, parentIsInsecure) => {
|
let hasInsecureLoginForms = (thisWindow, parentIsInsecure) => {
|
||||||
let doc = thisWindow.document;
|
let doc = thisWindow.document;
|
||||||
let isInsecure =
|
let isInsecure = parentIsInsecure || !this.isDocumentSecure(doc);
|
||||||
parentIsInsecure ||
|
|
||||||
!this.checkIfURIisSecure(doc.documentURIObject);
|
|
||||||
let hasLoginForm = !!this.stateForDocument(doc).loginForm;
|
let hasLoginForm = !!this.stateForDocument(doc).loginForm;
|
||||||
return (hasLoginForm && isInsecure) ||
|
return (hasLoginForm && isInsecure) ||
|
||||||
Array.some(thisWindow.frames,
|
Array.some(thisWindow.frames,
|
||||||
|
@ -1101,50 +1102,37 @@ var LoginManagerContent = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Checks whether the passed uri is secure
|
* Returns true if the provided document principal and URI are such that the
|
||||||
* Check Protocol Flags to determine if scheme is secure:
|
* page using them can safely host password fields.
|
||||||
* 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.
|
|
||||||
* "https",
|
|
||||||
* "moz-safe-about"
|
|
||||||
*
|
*
|
||||||
* The use of this logic comes directly from nsMixedContentBlocker.cpp
|
* This means the page can't be easily tampered with because it is sent over
|
||||||
* At the time it was decided to include these protocols since a secure
|
* an encrypted channel or is a local resource that never hits the network.
|
||||||
* uri for mixed content blocker means that the resource can't be
|
*
|
||||||
* easily tampered with because 1) it is sent over an encrypted channel or
|
* The system principal, codebase principals with secure schemes like "https",
|
||||||
* 2) it is a local resource that never hits the network
|
* and local schemes like "resource" and "file" are all considered secure. If
|
||||||
* or 3) it is a request sent without any response that could alter
|
* the page is sandboxed, then the document URI is checked instead.
|
||||||
* the behavior of the page. It was decided to include the same logic
|
*
|
||||||
* here both to be consistent with MCB and to make sure we cover all
|
* @param document
|
||||||
* "safe" protocols. Eventually, the code here and the code in MCB
|
* The document whose principal and URI are to be considered.
|
||||||
* will be moved to a common location that will be referenced from
|
|
||||||
* both places. Look at
|
|
||||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=899099 for more info.
|
|
||||||
*/
|
*/
|
||||||
checkIfURIisSecure : function(uri) {
|
isDocumentSecure(document) {
|
||||||
let isSafe = false;
|
let docPrincipal = document.nodePrincipal;
|
||||||
let netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil);
|
if (docPrincipal.isSystemPrincipal) {
|
||||||
let ph = Ci.nsIProtocolHandler;
|
return true;
|
||||||
|
|
||||||
// Is the connection to localhost? Consider localhost safe for passwords.
|
|
||||||
if (gContentSecurityManager.isURIPotentiallyTrustworthy(uri) ||
|
|
||||||
netutil.URIChainHasFlags(uri, ph.URI_IS_LOCAL_RESOURCE) ||
|
|
||||||
netutil.URIChainHasFlags(uri, ph.URI_DOES_NOT_RETURN_DATA) ||
|
|
||||||
netutil.URIChainHasFlags(uri, ph.URI_INHERITS_SECURITY_CONTEXT) ||
|
|
||||||
netutil.URIChainHasFlags(uri, ph.URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT)) {
|
|
||||||
|
|
||||||
isSafe = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return isSafe;
|
// Fall back to the document URI for sandboxed documents that do not have
|
||||||
|
// the allow-same-origin flag, as they have a null principal instead of a
|
||||||
|
// codebase principal. Here there are still some cases that are considered
|
||||||
|
// insecure while they are secure, for example sandboxed documents created
|
||||||
|
// using a "javascript:" or "data:" URI from an HTTPS page. See bug 1162772
|
||||||
|
// for defining "window.isSecureContext", that may help in these cases.
|
||||||
|
let uri = docPrincipal.isCodebasePrincipal ? docPrincipal.URI
|
||||||
|
: document.documentURIObject;
|
||||||
|
|
||||||
|
// These checks include "file", "resource", HTTPS, and HTTP to "localhost".
|
||||||
|
return gContentSecurityManager.isURIPotentiallyTrustworthy(uri);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
|
||||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
||||||
|
|
||||||
TESTING_JS_MODULES += [
|
TESTING_JS_MODULES += [
|
||||||
|
# Make this file available from the "resource:" URI of the test environment.
|
||||||
|
'test/browser/form_basic.html',
|
||||||
'test/LoginTestUtils.jsm',
|
'test/LoginTestUtils.jsm',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,13 @@ support-files =
|
||||||
insecure_test.html
|
insecure_test.html
|
||||||
insecure_test_subframe.html
|
insecure_test_subframe.html
|
||||||
multiple_forms.html
|
multiple_forms.html
|
||||||
|
streamConverter_content.sjs
|
||||||
|
|
||||||
[browser_DOMFormHasPassword.js]
|
[browser_DOMFormHasPassword.js]
|
||||||
[browser_DOMInputPasswordAdded.js]
|
[browser_DOMInputPasswordAdded.js]
|
||||||
[browser_filldoorhanger.js]
|
[browser_filldoorhanger.js]
|
||||||
[browser_hasInsecureLoginForms.js]
|
[browser_hasInsecureLoginForms.js]
|
||||||
|
[browser_hasInsecureLoginForms_streamConverter.js]
|
||||||
[browser_notifications.js]
|
[browser_notifications.js]
|
||||||
skip-if = true # Intermittent failures: Bug 1182296, bug 1148771
|
skip-if = true # Intermittent failures: Bug 1182296, bug 1148771
|
||||||
[browser_passwordmgr_editing.js]
|
[browser_passwordmgr_editing.js]
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/LoginManagerParent.jsm", this);
|
||||||
|
|
||||||
|
function* registerConverter() {
|
||||||
|
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||||
|
Cu.import("resource://gre/modules/NetUtil.jsm", this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the "test/content" MIME type, served by the test over HTTP, to an
|
||||||
|
* HTML viewer page containing the "form_basic.html" code. The viewer is
|
||||||
|
* served from a "resource:" URI while keeping the "resource:" principal.
|
||||||
|
*/
|
||||||
|
function TestStreamConverter() {}
|
||||||
|
|
||||||
|
TestStreamConverter.prototype = {
|
||||||
|
classID: Components.ID("{5f01d6ef-c090-45a4-b3e5-940d64713eb7}"),
|
||||||
|
contractID: "@mozilla.org/streamconv;1?from=test/content&to=*/*",
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([
|
||||||
|
Ci.nsIRequestObserver,
|
||||||
|
Ci.nsIStreamListener,
|
||||||
|
Ci.nsIStreamConverter,
|
||||||
|
]),
|
||||||
|
|
||||||
|
// nsIStreamConverter
|
||||||
|
convert() {},
|
||||||
|
|
||||||
|
// nsIStreamConverter
|
||||||
|
asyncConvertData(aFromType, aToType, aListener, aCtxt) {
|
||||||
|
this.listener = aListener;
|
||||||
|
},
|
||||||
|
|
||||||
|
// nsIRequestObserver
|
||||||
|
onStartRequest(aRequest, aContext) {
|
||||||
|
let channel = NetUtil.newChannel({
|
||||||
|
uri: "resource://testing-common/form_basic.html",
|
||||||
|
loadUsingSystemPrincipal: true,
|
||||||
|
});
|
||||||
|
channel.originalURI = aRequest.QueryInterface(Ci.nsIChannel).URI;
|
||||||
|
channel.loadGroup = aRequest.loadGroup;
|
||||||
|
channel.owner = Services.scriptSecurityManager
|
||||||
|
.createCodebasePrincipal(channel.URI, {});
|
||||||
|
// In this test, we pass the new channel to the listener but don't fire a
|
||||||
|
// redirect notification, even if it would be required. This keeps the
|
||||||
|
// test code simpler and doesn't impact the principal check we're testing.
|
||||||
|
channel.asyncOpen(this.listener, aContext);
|
||||||
|
},
|
||||||
|
|
||||||
|
// nsIRequestObserver
|
||||||
|
onStopRequest() {},
|
||||||
|
|
||||||
|
// nsIStreamListener
|
||||||
|
onDataAvailable() {},
|
||||||
|
};
|
||||||
|
|
||||||
|
let factory = XPCOMUtils._getFactory(TestStreamConverter);
|
||||||
|
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||||
|
registrar.registerFactory(TestStreamConverter.prototype.classID, "",
|
||||||
|
TestStreamConverter.prototype.contractID, factory);
|
||||||
|
this.cleanupFunction = function () {
|
||||||
|
registrar.unregisterFactory(TestStreamConverter.prototype.classID, factory);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for the given number of occurrences of InsecureLoginFormsStateChange
|
||||||
|
* on the given browser element.
|
||||||
|
*/
|
||||||
|
function waitForInsecureLoginFormsStateChange(browser, count) {
|
||||||
|
return BrowserTestUtils.waitForEvent(browser, "InsecureLoginFormsStateChange",
|
||||||
|
false, () => --count == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that hasInsecureLoginForms is false for a viewer served internally
|
||||||
|
* using a "resource:" URI.
|
||||||
|
*/
|
||||||
|
add_task(function* test_streamConverter() {
|
||||||
|
let originalBrowser = gBrowser.selectedBrowser;
|
||||||
|
|
||||||
|
yield ContentTask.spawn(originalBrowser, null, registerConverter);
|
||||||
|
|
||||||
|
let tab = gBrowser.addTab("http://example.com/browser/toolkit/components/" +
|
||||||
|
"passwordmgr/test/browser/streamConverter_content.sjs");
|
||||||
|
let browser = tab.linkedBrowser;
|
||||||
|
yield Promise.all([
|
||||||
|
BrowserTestUtils.switchTab(gBrowser, tab),
|
||||||
|
BrowserTestUtils.browserLoaded(browser),
|
||||||
|
// One event is triggered by pageshow and one by DOMFormHasPassword.
|
||||||
|
waitForInsecureLoginFormsStateChange(browser, 2),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Assert.ok(!LoginManagerParent.hasInsecureLoginForms(browser));
|
||||||
|
|
||||||
|
yield BrowserTestUtils.removeTab(tab);
|
||||||
|
|
||||||
|
yield ContentTask.spawn(originalBrowser, null, function* () {
|
||||||
|
this.cleanupFunction();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,6 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
function handleRequest(request, response) {
|
||||||
|
response.setHeader("Content-Type", "test/content", false);
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче