浏览器如何知道何时提示用户保存密码?
Posted
技术标签:
【中文标题】浏览器如何知道何时提示用户保存密码?【英文标题】:How does browser know when to prompt user to save password? 【发布时间】:2011-01-24 19:41:39 【问题描述】:这与我在这里提出的问题有关: How can I get browser to prompt to save password?
这是问题所在:我的浏览器无法提示我保存正在开发的网站的密码。 (我说的是当您在 Firefox 上提交表单时有时会出现的栏,上面写着“记住 yoursite.com 的密码?是/现在不/从不”)
这非常令人沮丧,因为 Firefox(以及大多数其他现代浏览器,我希望以类似的方式工作)的这个功能似乎是一个谜。这就像浏览器做的一个魔术,它在哪里查看你的代码,或者你提交的东西,或者其他东西,如果它“看起来”像一个带有用户名(或电子邮件地址)字段和密码字段的登录表单,它提供保存。
除了在这种情况下,它没有在我的用户使用我的登录表单后向他们提供该选项,这让我发疯了。 :-)
(我检查了我的 Firefox 设置——我没有告诉浏览器“从不”这个网站。它应该会提示。)
我的问题
Firefox 使用哪些启发式方法来了解何时提示用户保存?这应该不难回答,因为它就在 Mozilla 源代码中(我不知道在哪里看,否则我会尝试自己挖掘它)。我也没有找到来自 Mozilla 开发人员的博客文章或其他类似的开发人员说明。
(我可以为 Safari 或 IE 回答这个问题;我想所有的浏览器都使用非常相似的规则,所以如果我可以让它在其中一个中工作,它会在其他浏览器中工作。)
(* 请注意,如果您对我的回答与 cookie、加密或有关我如何在本地数据库中存储密码的任何其他内容有关,那么您很可能误解了我的问题。:-)
【问题讨论】:
我不知道。您的表单是带有密码类型字段的 POST 表单吗? 是的,包裹在 【参考方案1】:嗯,在our site 上,一个名为“username”的表单字段输入“text”,紧跟一个名为“password”并输入“password”的字段似乎可以解决问题。
【讨论】:
对我来说太快了!我的想法完全...(我正在删除我的答案) 是的。试过了。没有运气。 :-( 我的理论是我的页面上有浏览器不喜欢的其他内容/使其认为该页面没有登录表单...【参考方案2】:您应该查看Mozilla Password Manager Debugging 页面和扩展编写者的nsILoginManager docs(仅了解 Firefox 如何处理密码管理的基本技术细节)。您可以深入了解那里的答案以及那里链接的其他页面,以找到比您可能想知道的密码管理器如何与网站和扩展程序交互的更多信息。
(特别是在密码管理器调试文档中指出,请确保您没有在 html 中将自动完成设置为关闭,因为这将抑制保存用户名和密码的提示)
【讨论】:
【参考方案3】:根据我的阅读,我认为 Firefox 通过 form.elements[n].type == "password"
检测密码(遍历所有表单元素),然后通过在密码字段之前的文本字段的表单元素中向后搜索来检测用户名字段(更多信息here)。您可以在 javascript 中尝试类似的操作,看看是否可以检测到您的密码字段。
据我所知,您的登录表单必须是 <form>
的一部分,否则 Firefox 将无法检测到它。在您的密码字段上设置id="password"
可能也不会受到伤害。
如果这仍然给您带来很多问题,我建议您在 Mozilla 项目的开发者邮件列表之一上提问(您甚至可能会收到设计该功能的开发者的回复)。
【讨论】:
这太棒了。谢谢。这就是我要找的。span> 这帮助我让它在 Firefox 中工作,但我对 Chrome 没有任何运气。这是我正在使用的表单: @1.21gigawatts- 没有“标准”方式来做到这一点(据我所知),因此不同的浏览器可能会略有不同。我不知道 Chrome 的流程与 Firefox 的流程有何不同,但如果您查看 Chrome 源代码,您可能会弄清楚。我知道 Firefox 是如何做到这一点的唯一方法是阅读他们的代码。这是有人需要在大图表中记录的那种事情,列出每个浏览器是如何做到的...... 密码管理器代码的作者在 2013 年的一篇博文中向您介绍了一些事情——值得一读:blog.mozilla.org/dolske/2013/08/20/on-firefoxs-password-manager 更新了密码管理器博客文章的链接:dolske.wordpress.com/2013/08【参考方案4】:我遇到了同样的问题并找到了解决方案:
要让浏览器要求存储密码,用户名和密码框必须在表单中,并且必须实际提交该表单。提交按钮可能会从 onclick 处理程序返回 false(因此实际上不会发生提交)。
要让浏览器恢复以前存储的密码,输入框必须存在于主HTML表单中,而不是通过javascript动态创建。可以使用 display:none 创建表单。
需要注意的是,密码是在页面加载后立即填写的,并且在整个会话期间都存在,因此可以通过注入的 javascript 读取:这会使此类攻击变得更糟。为了避免这种情况,为了登录而转发到单独的页面是合理的,它解决了您开始阅读本主题的所有问题:)。作为部分解决方案,我在提交表单时清除字段 - 如果用户注销并想再次登录,则浏览器不会填写密码,但这对我来说是次要的。
维利亚姆
【讨论】:
在 Firefox 3.5 和 IE8 中有效,在 Chrome 中无效(第 1 点无效)。也许提交必须是真实的...... user324356 - 我将表单设置为“#”,然后调用 myForm.submit() 并且在 Firefox 中有效但 Chrome 没有提示。 仅供参考:当您使用return false
或 event.preventDefault()
时,由于此错误,这在 Chrome 中将不起作用:code.google.com/p/chromium/issues/detail?id=282488
这对于firefox当前使用的算法来说绝对重要——它不是密码管理器“寻找”的唯一东西,但firefox密码管理器不会在没有实际提交的情况下被触发。
更新:Chrome 46 修复了它的错误行为 - 现在一切正常。见***.com/a/33113374/810109【参考方案5】:
如果您使用 AJAX 登录,请查看该源代码:https://gist.github.com/968927
它包括向隐藏的 iframe 提交登录表单,以便 IE 和 Chrome 可以检测到实际登录,而无需重新加载页面。
【讨论】:
Chrome 46 修复了它的错误行为 - 不再需要iframe
变通方法。见***.com/a/33113374/810109【参考方案6】:
这里的启发式方法非常简单:以特定顺序检测具有特定名称的字段。哪些,我不知道,但这在 Chrome 和 IE 中对我来说很好:
Username field: name "login", type "text";
Password field: name "password", type "password"
Submit button: element "input", type "submit".
Element "button" type "submit" did not work.
【讨论】:
我必须将<button type="submit">
替换为 <input type="submit">
才能让 Dashlane 正常工作。不敢相信这甚至是一件事......【参考方案7】:
这似乎适用于 Mac 上的 Firefox、Chrome 和 Safari。未在 Windows 上测试。
<form id="bridgeForm" action="#" target="loginframe" autocomplete="on">
<input type="text" name="username" id="username" />
<input type="password" name="password" id="password"/>
</form>
<iframe id="loginframe" name="loginframe" src="anyblankpage.html"></iframe>
这需要添加到页面中。不能动态添加。可以将表单和 iframe 设置为 display:none。如果您没有设置 iframe 的 src,则在您至少提交一次表单之前不会显示提示。
然后调用form submit():
bridgeForm.submit();
操作可能是可选的,自动完成可能是可选的。没有测试过。
注意:在某些浏览器上,表单必须在服务器(不是本地主机,也不是文件系统)上运行,然后浏览器才会响应。
所以这个:
http://www.mysite.com/myPage.html
不是这个:
http://126.0.0.1/myPage.html
http://localhost/myPage.html
file://directory/myPage.html
【讨论】:
@ErikAronesty 你有解决方案吗?我注意到在某些浏览器(safari)中,页面必须在服务器上,而不是本地主机或文件系统上。 Chrome 46 修复了它的错误行为 - 不再需要iframe
变通方法。见***.com/a/33113374/810109【参考方案8】:
我还注意到,如果登录请求后登录表单仍然存在,Chrome 将不会提供记住密码,即使它隐藏在页面上。
我猜它认为登录操作失败,因此拒绝存储无效凭据。
在 Chrome 34.0 上可见。
【讨论】:
Chrome 46 修复了它的错误行为,在 ajax 请求之后隐藏表单就足够了。见***.com/a/33113374/810109【参考方案9】:适用于 angular、chrome、firefox:(我已经搜索和测试了几个小时 - 对于 chrome,表单操作参数 (#
) 就是答案。@1.21 gigawatts,谢谢!!!您的 @987654322 @ 是无价的。)
表格
firefox 30.0 - 不需要隐藏 iframe 和提交按钮(如下所示),但需要“login-form-autofill-fix”指令来识别自动填充的凭据,如下所示:
<form name="loginForm" login-form-autofill-fix action="#" target="emptyPageForLogin" method="post" ng-submit="login(loginName:grpEmail,password:grpPassword)">
<input type="text" name=username" id="username" ng-model="grpEmail"/>
<input type="password" name="password" id="password" ng-model="grpPassword"/>
<button type="submit">Login</button>
</form>
隐藏的 iframe
chrome 35.0 - 不需要上述指令,但需要隐藏 iframe 和真实表单上的提交按钮。隐藏的 iframe 看起来像
<iframe src="emptyPageForLogin.html" id="emptyPageForLogin" name="emptyPageForLogin" style="display:none"></iframe>
angular 指令(使用 jqLite)
这适用于角度 1.2.18
module.directive('loginFormAutofillFix', function()
return function(scope, elem, attrs)
if(!attrs.ngSubmit)
return;
setTimeout(function()
elem.unbind("submit").bind("submit", function(e)
//DO NOT PREVENT! e.preventDefault();
elem.find("input").triggerHandler("input");
scope.$apply(attrs.ngSubmit);
);
, 0);
);
修正
经过一些测试后,我意识到,chrome 需要通过 Angular 登录方法(200 毫秒)稍微超时 - 看来,对于密码管理器而言,重定向有时太快了。 更好地清除浏览器缓存...每次更改【讨论】:
由于最新的 chrome,pw-manager 有时只填写表格。密码管理器有时会弹出,有时不会...现在似乎是一个随机函数。 新版 Firefox 会忽略自动填写的密码字段。 triggerHandler("input") 不工作。这可以通过原生事件 (document.createEvent) 来解决 - 将其分派出去。 Chrome 46 修复了它的错误行为 - 不再需要iframe
解决方法。见***.com/a/33113374/810109
@110maor 我花了很长时间才理解你的帖子。我希望我的编辑符合您的意图。【参考方案10】:
我建议查看Firefox source code。它实际上是非常简单的代码。
您要查看的方法是_onFormSubmit
、_getFormFields
和_getPasswordFields
。
您甚至可能会发现您遇到的问题实际上是 Firefox 中一个未被发现的错误;)https://bugzilla.mozilla.org/show_bug.cgi?id=1211780
【讨论】:
【参考方案11】:主要关键字在这里,
<input type="password">
【讨论】:
尝试用更多细节来解释你的答案,因为这对其他人会有所帮助。【参考方案12】:除了已经说过的很多内容之外,我还意识到输入字段不能被“禁用”。我们有一个多步骤登录,首先要求输入用户名,然后在下一个屏幕上输入密码。在第二个屏幕上,我们重复了电子邮件,但禁用了它,这阻止了 Chrome 等。人。从识别为用户名的有效字段。
因为我们真的想保留那个禁用的输入字段,所以我们最终采用了这个 hacky 解决方法:
<input type="text" name="display-username" id="display-username" value="ENTERED_USERNAME" placeholder="Username" disabled="disabled">
<input type="text" name="username" id="username" value="ENTERED_USERNAME" placeholder="Username" style="display: none;">
<input type="password" name="password" id="password" value="" autofocus="autofocus" autocomplete="on" placeholder="Password" required="required">
我不会去推荐这个,但也许它会指出某人在他们自己的代码中的某些东西:
-
第一个元素在禁用的输入字段中显示用户名。 Disabled 不会作为表单的一部分提交,并且 disabled 不会被浏览器识别。
第二个元素是正确的输入字段,type = "text" 和 name/id = "username"。这正在被浏览器识别。为了防止用户对其进行编辑,我们使用 CSS (display:none) 将其隐藏。
【讨论】:
对于您希望输入的值已提交但用户无法更改的情况,您可能需要尝试“只读”而不是“禁用”。【参考方案13】:如果您在输入 type=password 之前的表单中有两个 type=text, 浏览器会为您的用户名检测最近的输入 type=text。
这无关紧要,另一个输入有 is=username 和 name=username
为了解决这个问题,您必须将您要保存的用户名输入准确地放在输入密码之前
祝你好运:-)
【讨论】:
以上是关于浏览器如何知道何时提示用户保存密码?的主要内容,如果未能解决你的问题,请参考以下文章