首页 文章

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

提问于
浏览
78

这与我在这里提出的问题有关:How can I get browser to prompt to save password?

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

这是非常令人沮丧的,因为Firefox(以及大多数其他现代浏览器,我希望以类似的方式工作)的这一功能似乎是一个谜 . 这就像浏览器所做的一个神奇技巧,它会查看您的代码,或者您提交的内容,或者某些东西,如果它“看起来”像一个带有用户名(或电子邮件地址)字段和密码字段的登录表单,它提供保存 .

除非在这种情况下,在他们使用我的登录表单后,它没有向我的用户提供该选项,这让我很疯狂 . :-)

(我检查了我的Firefox设置 - 我没有告诉浏览器“从不”这个网站 . 它应该是提示 . )

我的问题

Firefox使用什么启发式来了解何时应该提示用户保存?这应该不难回答,因为它就在Mozilla源代码中(我不知道在哪里看,否则我会尝试自己挖掘它) . 我也没有幸运地从Mozilla开发者那里找到博客文章或其他类似开发人员的说明 .

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

(*请注意,如果您对我的回答与cookie,加密或其他任何关于我如何在我的本地数据库中存储密码的问题有关,很可能你误解了我的问题 . :-)

13 回答

  • 51

    这里的启发式非常简单:以特定顺序检测具有某些名称的字段 . 哪些,我不知道,但这对我在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.
    
  • 10

    如果您在输入type = password之前在表单中有两个type = text,则浏览器会检测最近的输入类型=用户名的文本 .

    这不是另一个输入是= username和name = username

    要解决此问题,您必须在输入密码之前准确输入要保存的用户名输入

    祝好运 :-)

  • 0

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

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

    如果这仍然给你带来很多问题,我建议你询问一下Mozilla项目的开发人员邮件列表(你甚至可能会得到设计该功能的开发人员的回复) .

  • 3

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

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

    • 使浏览器恢复以前存储的密码,输入框必须存在于主HTML表单中,而不是通过javascript动态创建 . 可以使用display:none创建表单 .

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

    Viliam


  • 3

    您应该查看Mozilla Password Manager Debugging页面和nsILoginManager docs以获取扩展编写器(仅用于了解Firefox如何处理密码管理的详细技术细节) . 您可以深入了解那里的答案以及链接到那里的其他页面,以了解您可能想知道密码管理器如何与站点和扩展进行交互 .

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

  • 17

    这似乎适用于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提示在您提交表格至少一次之前,我们不会显示 .

    然后调用表单submit():

    bridgeForm.submit();
    

    该动作可以是可选的,并且自动完成可以是可选的 . 没有测试过 .

    Note :在某些浏览器上,表单必须在浏览器响应之前在服务器(而不是localhost而不是文件系统)上运行 .

    所以这:

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

    不是这个:

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

  • 6

    使用angular,chrome,firefox为我工作:(我已经搜索并测试了几个小时 - 对于chrome,表单操作参数( # )就是答案.@1.21 gigawatts,谢谢!!!你的answer非常宝贵 . )

    表格

    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通过角度登录方法(200ms)需要稍微超时 - 看起来,重定向有时对于密码管理器来说太快了 .

    • 更好地清除browsercache ...随着每一个变化

  • 1

    好吧,在our site上,一个名为"username"的表单字段"text"紧跟一个名为"password"且类型为"password"的字段,似乎可以解决问题 .

  • 3

    如果您正在使用AJAX登录,请查看该源代码:https://gist.github.com/968927

    它包括向隐藏的iframe提交登录表单,以便IE和Chrome可以检测实际登录,而无需重新加载页面 .

  • 2

    我还注意到,如果登录表单在登录请求后仍然存在,Chrome将不会记住密码,即使它隐藏在页面上也是如此 .

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

    在Chrome 34.0上看到 .

  • -1

    我建议看一下Firefox source code . 它实际上是非常简单的代码 .

    您要查看的方法是 _onFormSubmit_getFormFields_getPasswordFields .

    您甚至可能会发现您遇到的问题实际上是Firefox中未被发现的错误;)https://bugzilla.mozilla.org/show_bug.cgi?id=1211780

  • 6

    除了已经说过的很多内容之外,我还意识到输入字段不能被“禁用” . 我们有一个多步登录,首先要求输入用户名,然后在下一个屏幕上输入密码 . 在第二个屏幕上,我们重复了电子邮件但禁用了它,这阻止了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">
    

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

    • 第一个元素在禁用的输入字段中显示用户名 . 禁用不会被浏览器识别 .

    • 第二个元素是一个正确的输入字段,type = "text",name / id = "username" . 这被浏览器识别 . 为了防止用户编辑它,我们用CSS隐藏它(display:none) .

  • 3

    主要关键字在这里,

    <input type="password">
    

相关问题