如何防止浏览器存储密码


73

我需要停止浏览器存储用户名和密码值,因为我正在处理包含更多安全数据的Web应用程序。客户要求我这样做。

我尝试了autocomplete="off"HTML表单和密码字段中的属性。但它无法在最新的浏览器(例如Chrome 55,Firefox 38 +,Internet Explorer 11等)中运行。

最好的解决方案是什么?


1
我也遇到类似的情况-内部Web应用程序具有仅支持技术的区域,其中密码可解锁应用程序的不安全功能。允许最终用户访问此密码将是非常糟糕的,因此,是的,在某些情况下,您不希望保存密码。顺便说一句,仍在寻找一个可行的答案。
semmelbroesel

一个用例是用户共享计算机,但需要以个人身份登录到Webapp。
Leif Neland '18

我的解决方案有点破解,但是我使用JS清除了该字段。
大卫·莫里茨

1
我真的不建议人们在2020年这样做,除非您有非常特殊的情况。这会使安全性恶化。用户应该为他们使用的每项不同服务使用唯一的密码。当然,不可能记住那么多唯一且无关的密码,因此用户需要使用密码管理器来执行此操作。所有大型浏览器都有内置的浏览器,并且有很多第三方选项。除了一些特殊情况例外,阻止密码管理器可能最终会损害您的安全,而不是提供帮助。
克里斯,

Answers:


48

感谢您给我回复。我点击了以下链接

禁用浏览器的“保存密码”功能

我通过仅在输入中添加readonlyonfocus="this.removeAttribute('readonly');"属性autocomplete="off"来解决此问题,如下所示。

<input type="text" name="UserName" autocomplete="off" readonly 
onfocus="this.removeAttribute('readonly');" >

<input type="password" name="Password" autocomplete="off" readonly 
onfocus="this.removeAttribute('readonly');" >

这对我来说很好。


autocomplete浏览器不再支持该属性
csandreas1 '18年

2
尝试过这一点,也不能正常工作,尤其是Firefox开发人员版本
亚历山大

我的解决方案有点破解,但是我使用JS清除了该字段。
大卫·莫里茨

在我的登录页面(mvc项目)上,我添加了:onfocus =“ this.removeAttribute('readonly');”,onfocusout =“ this.setAttribute('readonly','readonly');” 它的魅力!即使在FireFox 67.0.4(64位)中!谢谢!
开发人员

在Firefox浏览器版本84.0b8(64位)中不起作用。
阿杰·塔库尔

39

这在现代浏览器中是不可能的,这是有充分理由的。现代浏览器提供了密码管理器,使用户可以使用比通常更强的密码。

MDN所述:如何关闭表单自动完成功能

现代浏览器实现了集成的密码管理:当用户输入站点的用户名和密码时,浏览器会为用户记住该密码。当用户再次访问该站点时,浏览器将使用存储的值自动填充登录字段。

此外,浏览器使用户能够选择一个主密码,该密码将被浏览器用来加密存储的登录详细信息。

即使没有主密码,浏览器内密码管理也通常被视为安全性的净收益。由于用户不必记住浏览器为他们存储的密码,因此他们可以选择比其他方式更强的密码。

因此,许多现代浏览器不支持autocomplete="off"登录字段:

  • 如果网站设置autocomplete="off"了表单,并且表单包含用户名和密码输入字段,则浏览器仍会记住该登录信息;如果用户同意,浏览器将在下次用户访问页面时自动填充这些字段。

  • 如果站点设置autocomplete="off"了用户名和密码输入字段,则浏览器仍会记住该登录信息;如果用户同意,浏览器将在下次用户访问页面时自动填充这些字段。

这是Firefox(自版本38),Google Chrome(自版本34)和Internet Explorer(自版本11)开始的行为。

如果作者希望阻止用户管理页面中密码字段的自动填充,在该页面中用户可以为自己以外的其他人指定新密码autocomplete="new-password",尽管尚未在所有浏览器中实现对此功能的支持。


3
如此,在浏览器中显示密码非常容易。只需打开开发人员工具,将输入类型从密码更改为文本,然后瞧!在那里。
艾罗伊·弗林

15
在某些情况下,密码管理器毫无意义。如更改密码。autocomplete =“ new-password”不适用于Firefox 55.0.3 x64
Pancho

谢谢,为我工作,这很简单。我使用的是Chome版本64.0.3282.186(正式版本)(64位)
A.Wie

6
在Chrome 65中,autocomplete="new-password"与我想要的完全相反。它不会显示“您想更新您保存的密码...”对话框吗?它只是默默地更新我存储的密码。比没用还糟-危险!> :(
道格·麦克莱恩

1
答案是不正确的,因为它在许多方面都是混乱的,有些简单,有些不是那么容易,但是有可能。浏览器并不限制信息呈现给用户的方式,而只是决定形状。
Lucian Minea

15

这是针对Chrome的纯HTML / CSS解决方案,已在65.0.3325.162版(正式版本)(64位)中进行了测试

设置输入type="text"并使用CSS text-security:disc进行模仿type="password"

<input type="text" name="username">
<input type="text" name="password" style="text-security:disc; -webkit-text-security:disc;">

据我测试过,该解决方案适用于ChromeFirefox版本59.0(64位)Internet Explorer版本11.0.9600以及IE仿真器Internet Explorer 5和更高版本。


4
考虑到密码字段还具有其他一些安全属性,例如,无法在其中复制粘贴文本,因此这可能是个坏主意。
tXK

1
@tXK我同意你的要求..但是您可以通过快速技巧将文本复制/粘贴到密码字段中,例如,在chrome中,右键单击密码字段,转到进行检查,然后将type =“ password”更改为type =“文本”。
Natro90 '18

3
在密码字段中不应将复制/粘贴视为问题,因为这是密码管理器的理论基础。问特洛伊·亨特。
罗伦佐·佩尼亚

我认为这不是一个好主意。例如,如果我们有自动文件管理器或密码管理器扩展,它如何识别密码字段,可能有一些选项可以找到它..但是对初学者来说,这不是一个好课程
Khurram Shaikh

这是在React with Chrome上对我真正有效的唯一解决方案。
Luis Febro'3

10

您应该能够制作一个假的隐藏密码框来防止它。

<form>
  <div style="display:none">
    <input type="password" tabindex="-1"/>
  </div>
  <input type="text" name="username" placeholder="username"/>
  <input type="password" name="password" placeholder="password"/>
</form>


天才!:)我会给它一个值,例如value =“ x”。而且我不会使用display:none,而是使用窗口外的荒谬位置或负Z索引。
FlorianB

<input type =“ hidden”>呢?
qd0r

在浏览器firefox 84.0b5(64位)版本中,它不起作用。
阿杰伊·塔库尔

9

我通过添加autocomplete="one-time-code"密码输入解决了这个问题。

根据HTML参考 autocomplete="one-time-code"-用于验证用户身份的一次性代码。看起来最适合这个。


6

默认情况下,没有任何适当的答案可禁用在浏览器中保存密码。但幸运的是,有一种解决方法,它几乎可以在所有浏览器中使用。

为此,请在实际输入之前添加一个伪输入,并使用autocomplete =“ off”和一些自定义样式将其隐藏并提供tabIndex。

某些浏览器(Chrome)的自动完成功能会填充找到的第一个密码输入,以及之前输入的密码,因此使用此技巧,它只会填充无关紧要的不可见输入。

          <div className="password-input">
            <input
              type="password"
              id="prevent_autofill"
              autoComplete="off"
              style={{
                opacity: '0',
                position: 'absolute',
                height: '0',
                width: '0',
                padding: '0',
                margin: '0'
              }}
              tabIndex="-2"
            />
            <input
              type="password"
              autoComplete="off"
              className="password-input-box"
              placeholder="Password"
              onChange={e => this.handleChange(e, 'password')}
            />
          </div>

3

我测试了许多解决方案,最后得到了这个解决方案。

HTML代码

<input type="text" name="UserName" id="UserName" placeholder="UserName" autocomplete="off" />
<input type="text" name="Password" id="Password" placeholder="Password" autocomplete="off"/>

CSS代码

#Password {
    text-security: disc;
    -webkit-text-security: disc;
    -moz-text-security: disc;
}

JavaScript代码

window.onload = function () {
    init();
}

function init() {
    var x = document.getElementsByTagName("input")["Password"];
    var style = window.getComputedStyle(x);
    console.log(style);

    if (style.webkitTextSecurity) {
        // Do nothing
    } else {
        x.setAttribute("type", "password");
    }
}

2

在发布此消息时,以前的答案都对我不起作用。

此方法使用可见的密码字段来捕获用户的密码,并使用隐藏的密码字段来将密码传递给服务器。提交表单之前,可见的密码字段为空白,但没有表单submit事件处理程序(请参阅下一段的说明)。这种方法将可见密码字段值尽快(没有不必要的开销)传输到隐藏密码字段,然后清除可见密码字段。如果用户跳回到可见的密码字段,则将恢复该值。清除字段后,它将使用占位符显示●●●。

我尝试清除表单onsubmit事件上的可见密码字段,但浏览器似乎正在检查事件处理程序之前的值,并提示用户保存密码。实际上,如果未alert对末尾的passwordchange注释,浏览器仍会提示您保存密码。

function formsubmit(e) {
  document.getElementById('form_password').setAttribute('placeholder', 'password');
}

function userinputfocus(e) {
  //Just to make the browser mark the username field as required
  // like the password field does.
  e.target.value = e.target.value;
}

function passwordfocus(e) {
  e.target.setAttribute('placeholder', 'password');
  e.target.setAttribute('required', 'required');
  e.target.value = document.getElementById('password').value;
}

function passwordkeydown(e) {
  if (e.key === 'Enter') {
    passwordchange(e.target);
  }
}

function passwordblur(e) {
  passwordchange(e.target);

  if (document.getElementById('password').value !== '') {
    var placeholder = '';
      
    for (i = 0; i < document.getElementById('password').value.length; i++) {
      placeholder = placeholder + '●';
    }
      
    document.getElementById('form_password').setAttribute('placeholder', placeholder);
  } else {
    document.getElementById('form_password').setAttribute('placeholder', 'password');
  }
}

function passwordchange(password) {
  if (password.getAttribute('placeholder') === 'password') {
    if (password.value === '') {
      password.setAttribute('required', 'required');
    } else {
      password.removeAttribute('required');
      var placeholder = '';

      for (i = 0; i < password.value.length; i++) {
        placeholder = placeholder + '●';
      }
    }

    document.getElementById('password').value = password.value;
    password.value = '';

    //This alert will make the browser prompt for a password save
    //alert(e.type);
  }
}
#form_password:not([placeholder='password'])::placeholder {
  color: red; /*change to black*/
  opacity: 1;
}
<form onsubmit="formsubmit(event)" action="/action_page.php">
<input type="hidden" id="password" name="password" />

<input type="text" id="username" name="username" required
  autocomplete="off" placeholder="username"
  onfocus="userinputfocus(event)" />
<input type="password" id="form_password" name="form_password" required
  autocomplete="off" placeholder="password"
  onfocus="passwordfocus(event)"
  onkeydown="passwordkeydown(event)"
  onblur="passwordblur(event)"/>
<br />
<input type="submit"/>


1
< input type="password" style='pointer-event: none' onInput= (e) => handleInput(e) />
function handleInput(e) {
  e.preventDefault();
  e.stopPropagation();
  e.target.setAttribute('readonly', true);
  setTimeout(() => {
    e.target.focus();
    e.target.removeAttribute('readonly');
  });
}

一个解释将是有条理的。
彼得·莫滕森

0

这为我工作:

<form action='/login' class='login-form' autocomplete='off'>
  User:
  <input type='user' name='user-entry'>
  <input type='hidden' name='user'>

  Password:
  <input type='password' name='password-entry'>
  <input type='hidden' name='password'>
</form>

注意:并非所有浏览器都支持自动完成属性!
摘要

0

我认为在最新的浏览器中是不可能的。

唯一的方法是采用另一个隐藏的密码字段,并在提交可见的密码字段中的值之后,将其用作逻辑,然后将虚拟字符串放在可见的密码字段中。

在这种情况下,浏览器可以存储虚拟字符串而不是实际密码。


0

尽管先前的解决方案非常正确,但是如果您绝对需要该功能,则可以使用文本字段和JavaScript通过自定义输入来模拟这种情况。

为了安全使用,您可以使用任何加密技术。因此,这种方式将绕过浏览器的密码保存行为。

如果您想进一步了解这个想法,我们可以在聊天中讨论。但是要点在前面的答案中已经讨论过,您可以理解这个主意。


0

请尝试以下方法。可能会对您有所帮助。

有关更多信息,请访问Input type = password,不要让浏览器记住密码

function setAutoCompleteOFF(tm) {
    if(typeof tm == "undefined") {
        tm = 10;
    }
    try {
        var inputs = $(".auto-complete-off, input[autocomplete=off]");
        setTimeout(function() {
            inputs.each(function() {
                var old_value = $(this).attr("value");
                var thisobj = $(this);
                setTimeout(function() {
                    thisobj.removeClass("auto-complete-off").addClass("auto-complete-off-processed");
                    thisobj.val(old_value);
                }, tm);
             });
         }, tm);
    }
    catch(e){
    }
}

$(function(){
    setAutoCompleteOFF();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="passfld" type="password" autocomplete="off" />
<input type="submit">


0

一种方法是生成随机输入名称并使用它们。

这样,浏览器new每次都会显示表单,并且无法预先填充输入字段。

如果您提供一些示例代码(您是否有JavaScript单页应用程序(SPA)应用程序或某些服务器端渲染),我们将很乐意为您提供帮助。


这不起作用-即使该字段没有名称或ID(无论如何在Firefox上),密码管理器都会提示输入
Pancho

0

几年前,我有一个特殊的情况需要这样做:两个知道其网络密码的人同时访问同一台计算机以签署法律协议。

您不希望在这种情况下保存任何一个密码,因为保存密码是一个法律问题,而不是一个技术性问题,因为这两个方面的物理和时间上的存在都是强制性的。现在,我同意这是一种罕见的情况,但是这种情况确实存在,并且Web浏览器中的内置密码管理器没有帮助。

对于上述问题,我的技术解决方案是在passwordtext类型之间进行交换,并在字段为纯文本字段时使背景颜色与文本颜色匹配(从而继续隐藏密码)。浏览器不要求保存存储在纯文本字段中的密码。

jQuery插件:

https://github.com/cubiclesoft/php-flexforms-modules/blob/master/password-manager/jquery.stoppasswordmanager.js

来自以上链接的相关源代码:

(function($) {
$.fn.StopPasswordManager = function() {
    return this.each(function() {
        var $this = $(this);

        $this.addClass('no-print');
        $this.attr('data-background-color', $this.css('background-color'));
        $this.css('background-color', $this.css('color'));
        $this.attr('type', 'text');
        $this.attr('autocomplete', 'off');

        $this.focus(function() {
            $this.attr('type', 'password');
            $this.css('background-color', $this.attr('data-background-color'));
        });

        $this.blur(function() {
            $this.css('background-color', $this.css('color'));
            $this.attr('type', 'text');
            $this[0].selectionStart = $this[0].selectionEnd;
        });

        $this.on('keydown', function(e) {
            if (e.keyCode == 13)
            {
                $this.css('background-color', $this.css('color'));
                $this.attr('type', 'text');
                $this[0].selectionStart = $this[0].selectionEnd;
            }
        });
    });
}
}(jQuery));

演示:

https://barebonescms.com/demos/admin_pack/admin.php

单击菜单中的“添加条目”,然后滚动到页面底部的“模块:停止密码管理器”。


对于该演示,Chrome要求保存密码Version 65.0.3325.146
J. Allen

已确认。Chrome 63似乎没有这种行为。看起来在Chrome 64中按下Enter键之前,在调用元素上的模糊处理程序之前提交了表单,因此Chrome看到了密码字段。但是,如果您先单击该元素之外的元素然后提交,Chrome不会抱怨。在我看来,似乎是Chrome中的错误:提交表单之前,应始终在focus元素上调用所有相关的事件处理程序,因为可能需要运行验证代码以阻止提交表单。Firefox和Edge都在这里做正确的事。
CubicleSoft

上述错误和我遇到的另一个错误已修复。
CubicleSoft

该修补程序的工作方式是隐藏弹出窗口,但是仍然可以查看密码。用户可以单击chrome URL栏中的“键”图标,如果他们知道操作系统的帐户密码,则可以查看在任何密码文本输入中输入的最后一个已知密码。据我所知,表格甚至不必提交。现在在提交之前刷新页面还不够。所以我的理论是必须立即将击键记录到任何输入type = password中,而不要事后读取dom元素。
J.艾伦,

因此,Chrome附带了自己的密码DOM记录器。太棒了 这正是每个人都需要的。按设计中断的Web浏览器功能已损坏。Firefox和Edge没有这个问题。除了希望Google放弃非功能性,没有什么可以做的,当然,除非有人想发疯并完全用Javascript模拟密码字段。
CubicleSoft

0

您可以做的一件事就是要求您的用户禁用保存您网站的密码。这可以在浏览器范围内或起源范围内完成。

您可以做的另一件事是在页面加载后(以及浏览器自动完成字段之后)强制输入为空。将此脚本放在<body>元素的末尾。

userIdInputElement.value = "";
userPasswordInputElement.value = "";

0

我将创建一个会话变量并将其随机化。然后根据会话变量构建id和name值。然后在登录时询问您创建的会话var。

if (!isset($_SESSION['autoMaskPassword'])) {
    $bytes = random_bytes(16);
    $_SESSION['autoMask_password'] = bin2hex($bytes);
}

<input type="password" name="<?=$_SESSION['autoMaskPassword']?>" placeholder="password">

0

我通过将输入字段设置为“文本”,并捕获并操纵输入键来完成此操作

首先激活一个功能来捕捉按键

yourInputElement.addEventListener('keydown', onInputPassword);

onInputPassword函数是这样的:(假设您在某处定义了“ password”变量)

onInputPassword( event ) {
  let key = event.key;
  event.preventDefault(); // this is to prevent the key to reach the input field

  if( key == "Enter" ) {
    // here you put a call to the function that will do something with the password
  }
  else if( key == "Backspace" ) {
    if( password ) {
      // remove the last character if any
      yourInputElement.value = yourInputElement.value.slice(0, -1);
      password = password.slice(0, -1);
    }
  }
  else if( (key >= '0' && key <= '9') || (key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z') ) {
    // show a fake '*' on input field and store the real password
    yourInputElement.value = yourInputElement.value + "*";
    password += key;
  }
}

因此所有字母数字键都将添加到密码中,“退格”键将删除一个字符,“输入”键将终止,其他所有键均将被忽略

不要忘记在结尾处调用removeEventListener('keydown',onInputPassword)


-1

密码字段可以防止记住其历史记录,这很好用:

$('#multi_user_timeout_pin').on('input keydown', function(e) {
  if (e.keyCode == 8 && $(this).val().length == 1) {
    $(this).attr('type', 'text');
    $(this).val('');
  } else {
    if ($(this).val() !== '') {
      $(this).attr('type', 'password');
    } else {
      $(this).attr('type', 'text');
    }
  }

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" id="multi_user_timeout_pin" name="multi_user_pin" autocomplete="off" class="form-control" placeholder="Type your PIN here" ng-model="logutUserPin">


-1

我只是在单击事件之前将字段密码的type属性更改为hidden:

document.getElementById("password").setAttribute("type", "hidden");
document.getElementById("save").click();

-1

在这种情况下,我会在内部JavaScript代码检索到原始密码之后,而在提交表单之前,使用一些随机字符填充密码字段。

注意:表单肯定会将实际密码用于下一步。该值首先传输到隐藏字段。请参见代码示例。

这样,当浏览器的密码管理器保存密码时,它实际上并不是用户在那里输入的密码。因此,用户认为密码已经保存,实际上是保存了一些随机的东西。随着时间的流逝,用户将知道他/她不能信任密码管理器为该站点执行正确的工作。

现在,这可能会导致不良的用户体验;我知道,因为用户可能会觉得浏览器确实保存了密码。但是只要有足够的文档,就可以对用户进行管理。我认为这是一种完全可以确保用户输入的实际密码不能被浏览器获取并保存的方式。

<form id='frm' action="https://google.com">
    Password: <input type="password" id="pwd" />
    <input type='hidden' id='hiddenpwd' />
    <button onclick='subm()'>Submit this</button>
</form>

<script>
    function subm() {
        var actualpwd = $('#pwd').val();
        $('#hiddenpwd').val(actualpwd);
        // ...Do whatever Ajax, etc. with this actual pwd
        // ...Or assign the value to another hidden field
        $('#pwd').val('globbedygook');
        $('#frm').submit();
    }
</script>

@AristeidisKaravas网络上的多个银行应用程序都使用此方法来确保从未存储实际密码-它们用任意字符填充密码字段,只是使浏览器密码管理器感到困惑
S. Francis
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.