浏览器如何知道何时提示用户保存密码?


82

这与我在这里提出的问题有关: 如何让浏览器提示您保存密码?

这是问题所在:我无法让浏览器提示我保存我正在开发的网站的密码。(我说的是,当您在Firefox上提交表单时,有时会显示的栏,上面写着“还记得yoursite.com的密码吗?是/不是现在/从不”)

这真令人沮丧,因为Firefox(和大多数其他现代浏览器,我希望以类似的方式工作)的这一功能似乎是个谜。这就像浏览器的魔术一样,在浏览器中查看您的代码,提交的内容或其他内容,如果它“看上去”像是带有用户名(或电子邮件地址)字段和密码字段的登录表单,保存。

除非在这种情况下,否则在我的用户使用我的登录表单后,它没有为我的用户提供该选项,这使我发疯。:-)

(我检查了Firefox的设置-我没有告诉浏览器“从不”访问该站点。它应该在提示。)

我的问题

Firefox用来了解何时提示用户进行保存的启发式操作是什么?这应该不太难回答,因为它就在Mozilla源码中(我不知道在哪里看,否则我会尝试自己挖掘出来)。我也没有运气找到Mozilla开发人员关于此的博客帖子或其他类似的开发人员说明。

(我可以在Safari或IE中回答这个问题,这很好;我可以想象所有浏览器的用户使用的规则都非常相似,因此,如果我能在其中一个浏览器中使用它,那么它将在其他浏览器中使用。)

(*请注意,如果您对我的回答与Cookie,加密或其他与我在本地数据库中存储密码的方式有关,则很可能是您误解了我的问题。:-)


1
我不知道。您的表单是带有密码类型字段的POST表单吗?
zneak

2
是的,包装在<form>标记中,并且这些字段分别名为“用户名”和“密码”。我使用AJAX将其加载为一个单独的层,但disqus.com也是如此(仅在此处举一个示例),它对他们来说非常有用。这就是为什么我要找出浏览器的确切想法,而不是(继续)随机地进行调整以查看它是否有所帮助。
艾瑞克(Eric)2010年

Answers:


55

基于我所读的内容,我认为Firefox通过form.elements[n].type == "password"(遍历所有表单元素)检测密码,然后通过在表单元素中向后搜索紧接密码字段之前的文本字段来检测用户名字段(此处提供更多信息)。您可以尝试使用Javascript中的类似方法,看看是否可以检测到密码字段。

据我所知,您的登录表单必须是的一部分,<form>否则Firefox将无法检测到它。id="password"在密码字段上进行设置也可能不会受到伤害。

如果这仍然给您带来很多问题,我建议您向Mozilla项目的开发者邮件列表之一提问(您甚至可能会从设计该功能的开发者那里得到答复)。


2
太好了 谢谢。这就是我想要的。
埃里克(Eric)2010年

1
这有助于我使其在Firefox中正常工作,但Chrome运气不佳。这是我使用的表格:<form id =“ myForm” action =“#”> <input id =“ username”> <input id =“ password” type =“ password”> </ form>
1.21吉瓦

3
@ 1.21gigawatts-(据我所知)没有“标准”方式来执行此操作,因此不同的浏览器可能会略有不同。我不知道Chrome的过程与Firefox的过程有何不同,但是如果您浏览Chrome的源代码,您也许可以弄清楚。我知道Firefox如何做到的唯一方法是阅读他们的代码。有人需要在一张大图表中记录这种事情,列出每种浏览器的工作方式...
bta 2012

3
密码管理器代码的作者将引导您完成的事情在2013年的博客文章-这是一个值得读:blog.mozilla.org/dolske/2013/08/20/on-firefoxs-password-manager
DAT

2
更新至密码管理器博客文章的链接:dolske.wordpress.com/2013/08
Vsevolod Golovanov

17

我遇到了同样的问题,找到了解决方案:

  1. 为了使浏览器要求存储密码,用户名和密码框必须采用表格形式,并且该表格必须实际提交。提交按钮可能会从onclick处理程序返回false(因此实际上不会发生提交)。

  2. 为了使浏览器恢复先前存储的密码,输入框必须存在于主HTML表单中,并且不能通过javascript动态创建。可以使用display:none创建表单。

需要注意的是,密码是在页面加载后立即填充的,并且在整个会话期间都存在,因此可以通过注入的javascript读取:这样会使攻击变得更糟。为避免这种情况,转发到单独的页面以进行登录是合理的,它解决了您开始阅读本主题所涉及的所有问题:)。作为部分解决方案,我在提交表单时清除了这些字段-如果用户注销并想再次登录,浏览器不会填充密码,但这对我来说是次要的。

维利亚姆



在Firefox 3.5和IE8中有效,在Chrome中不起作用(第1点无效)。也许提交必须是真实的……
user324356 '04

user324356-我将表单设置为“#”,然后命名为myForm.submit(),该表单在Firefox中有效,但Chrome没有提示。
1.21吉瓦2012年

1
fyi:使用return falseevent.preventDefault()由于以下错误而无法在Chrome中使用:code.google.com/p/chromium/issues/detail?
id=282488

对于firefox使用的当前算法,这绝对是重要的-这不是密码管理器“寻找”的唯一内容,但是不会在没有实际提交的情况下触发firefox密码管理器。
dat 2015年

更新:Chrome 46修复了错误行为-现在一切正常。请参阅stackoverflow.com/a/33113374/810109
mkurz 2015年

10

您应该查看Mozilla密码管理器调试页面和扩展作家的nsILoginManager文档(仅适用于Firefox如何处理密码管理的具体技术细节)。您可以在此处找到答案以及在其上链接的其他页面,以查找比您可能想知道的密码管理器如何与站点和扩展交互的更多信息。

(特别是如密码管理器调试文档中所指出的那样,请确保您没有在html中将自动完成功能设置为关闭,因为这将禁止提示保存用户名和密码)


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可以设置为显示:无。如果您未设置iframe的src,则直到您至少提交一次表单后才会显示提示。

然后调用表单submit():

bridgeForm.submit();

该操作可以是可选的,而自动完成功能可以是可选的。还没测试。

注意:在某些浏览器上,表单必须在服务器(不是localhost而不是文件系统)上运行,然后浏览器才能响应。

所以这:

http://www.mysite.com/myPage.html

不是这个:

http://126.0.0.1/myPage.html
http://localhost/myPage.html
file://directory/myPage.html


@ErikAronesty您有解决方案吗?我注意到在某些浏览器(野生动物园)中,页面必须位于服务器上,而不是本地主机或文件系统上。
2014年

1
Chrome 46修复了错误的行为-不再iframe需要任何解决方法。请参阅stackoverflow.com/a/33113374/810109
mkurz 2015年

6

适用于我使用有角,镀铬和Firefox的设备:(我已经搜索并测试了数小时-对于镀铬#,答案是表单动作参数()。@ 1.21吉瓦,谢谢!!!!您的答案非常宝贵。)

形成

firefox 30.0-不需要隐藏的iframe和Submit按钮(如下所示),但是需要“ 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>

角度指令(使用jqLit​​e)

这适用于角度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需要通过角度登录方法(200ms)稍微超时-看来,对于密码管理器来说,重定向有时太快了。
  • 更好地清除浏览器缓存...进行每次更改

自从最新的chrome以来,pw-manager有时仅填写表格。pw管理器有时会弹出,有时却不会...现在似乎是一个随机函数。
110maor 2014年

新的Firefox将忽略自动填充的密码字段。triggerHandler(“ input”)无法正常工作。这可以通过本机事件(document.createEvent)来解决-向其调度。
110maor

1
Chrome 46修复了错误的行为-不再iframe需要任何解决方法。请参阅stackoverflow.com/a/33113374/810109
mkurz 2015年

@ 110maor我花了很长时间了解您的帖子。希望我的修改符合您的意图。
jpaugh

3

好吧,在我们的网站上,名称为“用户名”,“文本”的表单字段紧随其后的是名称为“ password”和类型为“ password”的字段似乎可以解决问题。


对我来说太快了!我的想法正好...(我要删除答案)
Ganesh Shankar,2010年

是。试过了。没运气。:-(我的理论是,页面上还有其他浏览器不喜欢的东西,或者使它认为该页面没有登录表格...
Eric


3

启发式方法在这里非常简单:按特定顺序检测具有特定名称的字段。我不知道哪一个,但这在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工作。不过,
简直

3

我还注意到,如果登录请求后仍然存在登录表单,即使该表单已隐藏在页面中,Chrome也不会提供记住密码的功能。

我猜它认为登录操作失败,因此拒绝存储无效的凭据。

在Chrome 34.0上看到。


1
Chrome 46修复了错误的行为,在ajax请求之后隐藏表单就足够了。请参阅stackoverflow.com/a/33113374/810109
mkurz 2015年


0

除了已经说了很多之外,我还意识到输入字段一定不能被“禁用”。我们进行了多步登录,首先要求输入用户名,然后在下一个屏幕上要求输入密码。在第二个屏幕上,我们重复了电子邮件,但禁用了该电子邮件,从而阻止了Chrome等。等 识别为用户名的有效字段。

由于我们确实想保留该禁用的输入字段,因此最终遇到了这种棘手的解决方法:

<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">

我不会推荐它,但也许它会指出某人在他们自己的代码中的某些东西:

  1. 第一个元素在禁用的输入字段中显示用户名。禁用不作为表单的一部分提交,并且浏览器无法识别禁用。
  2. 第二个元素是一个正确的输入字段,其类型为“ text”,名称/ id =“ username”。这已被浏览器识别。为了防止用户对其进行编辑,我们使用CSS将其隐藏(显示:无)。

对于需要输入值已提交但用户无法更改的输入的情况,您可能需要尝试“只读”而不是“禁用”。
大卫·布朗

0

例如,如果您的表单中输入type = password之前有两个type = text,则浏览器会检测到您的用户名最近的输入type = text。

没关系,另一个输入具有is = username和name = username

为解决此问题,您必须将要保存的用户名输入恰好放在输入密码之前

祝好运 :-)


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.