From c962e2051a1f3767a221254487bcfc6d53aa59a1 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 28 Feb 2019 10:02:19 +0100 Subject: WIP fix 1 --- .../passwordmgr/nsLoginManagerPrompter.js | 48 +++++++++++++--------- 1 file changed, 29 insertions(+), 19 deletions(-) (limited to 'toolkit') diff --git a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js index 720e80446..35315110c 100644 --- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js +++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js @@ -97,17 +97,25 @@ LoginManagerPromptFactory.prototype = { return; } - // Allow only a limited number of authentication dialogs when they are all - // canceled by the user. - var cancelationCounter = (prompter._browser && prompter._browser.canceledAuthenticationPromptCounter) || { count: 0, id: 0 }; - if (prompt.channel) { - var httpChannel = prompt.channel.QueryInterface(Ci.nsIHttpChannel); - if (httpChannel) { - var windowId = httpChannel.topLevelContentWindowId; - if (windowId != cancelationCounter.id) { - // window has been reloaded or navigated, reset the counter - cancelationCounter = { count: 0, id: windowId }; - } + // Set up a counter for ensuring that the basic auth prompt can not + // be abused for DOS-style attacks. With this counter, each eTLD+1 + // per browser will get a limited number of times a user can + // cancel the prompt until we stop showing it. + let browser = prompter._browser; + let baseDomain = null; + if (browser) { + try { + baseDomain = Services.eTLD.getBaseDomainFromHost(hostname); + } catch (e) { + baseDomain = hostname; + } + + if (!browser.authPromptCounter) { + browser.authPromptCounter = {}; + } + + if (!browser.authPromptCounter[baseDomain]) { + browser.authPromptCounter[baseDomain] = 0; } } @@ -137,13 +145,14 @@ LoginManagerPromptFactory.prototype = { prompt.inProgress = false; self._asyncPromptInProgress = false; - if (ok) { - cancelationCounter.count = 0; - } else { - cancelationCounter.count++; - } - if (prompter._browser) { - prompter._browser.canceledAuthenticationPromptCounter = cancelationCounter; + if (browser) { + // Reset the counter state if the user replied to a prompt and actually + // tried to login (vs. simply clicking any button to get out). + if (ok && (prompt.authInfo.username || prompt.authInfo.password)) { + browser.authPromptCounter[baseDomain] = 0; + } else { + browser.authPromptCounter[baseDomain] += 1; + } } } @@ -168,8 +177,9 @@ LoginManagerPromptFactory.prototype = { var cancelDialogLimit = Services.prefs.getIntPref("prompts.authentication_dialog_abuse_limit"); + let cancelationCounter = browser.authPromptCounter[baseDomain]; this.log("cancelationCounter =", cancelationCounter); - if (cancelDialogLimit && cancelationCounter.count >= cancelDialogLimit) { + if (cancelDialogLimit && cancelationCounter >= cancelDialogLimit) { this.log("Blocking auth dialog, due to exceeding dialog bloat limit"); delete this._asyncPrompts[hashKey]; -- cgit v1.2.3 From c1ece93c2be6fb571a013f9735dc629d7279f389 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 1 Mar 2019 14:01:09 +0100 Subject: Make the Auth prompt DOS protection a browser-element opt-in feature. --- .../passwordmgr/nsLoginManagerPrompter.js | 32 +++++++++++++++------- toolkit/content/widgets/browser.xml | 4 +++ 2 files changed, 26 insertions(+), 10 deletions(-) (limited to 'toolkit') diff --git a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js index 35315110c..c4be39e31 100644 --- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js +++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js @@ -103,7 +103,7 @@ LoginManagerPromptFactory.prototype = { // cancel the prompt until we stop showing it. let browser = prompter._browser; let baseDomain = null; - if (browser) { + if (browser && browser.isAuthDOSProtected) { try { baseDomain = Services.eTLD.getBaseDomainFromHost(hostname); } catch (e) { @@ -145,7 +145,7 @@ LoginManagerPromptFactory.prototype = { prompt.inProgress = false; self._asyncPromptInProgress = false; - if (browser) { + if (browser && browser.isAuthDOSProtected) { // Reset the counter state if the user replied to a prompt and actually // tried to login (vs. simply clicking any button to get out). if (ok && (prompt.authInfo.username || prompt.authInfo.password)) { @@ -177,15 +177,27 @@ LoginManagerPromptFactory.prototype = { var cancelDialogLimit = Services.prefs.getIntPref("prompts.authentication_dialog_abuse_limit"); - let cancelationCounter = browser.authPromptCounter[baseDomain]; - this.log("cancelationCounter =", cancelationCounter); - if (cancelDialogLimit && cancelationCounter >= cancelDialogLimit) { - this.log("Blocking auth dialog, due to exceeding dialog bloat limit"); - delete this._asyncPrompts[hashKey]; - - // just make the runnable cancel all consumers - runnable.cancel = true; + // Block the auth prompt if: + // - There is an attached browser element + // - The browser element has opted-in to DOS protection + // - The dialog cancellation limit is not 0 (= feature disabled) + // - The amount of cancellations >= the set abuse limit + if (browser && browser.isAuthDOSProtected) { + let cancelationCounter = browser.authPromptCounter[baseDomain]; + this.log("cancelationCounter =", cancelationCounter); + + if (cancelDialogLimit && cancelationCounter >= cancelDialogLimit) { + this.log("Blocking auth dialog, due to exceeding dialog bloat limit"); + delete this._asyncPrompts[hashKey]; + + // just make the runnable cancel all consumers + runnable.cancel = true; + } else { + this._asyncPromptInProgress = true; + prompt.inProgress = true; + } } else { + // No DOS protection: prompt this._asyncPromptInProgress = true; prompt.inProgress = true; } diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml index a30ff1c43..5a0a99bf8 100644 --- a/toolkit/content/widgets/browser.xml +++ b/toolkit/content/widgets/browser.xml @@ -899,6 +899,10 @@ null + + null -- cgit v1.2.3