现代浏览器是否能够真正禁用密码字段的自动填充和自动完成?

8

现代浏览器的自动填充和自动完成标准是完全忽略放在form中的密码字段的autocomplete="off"。即使在用户管理页面中保存的密码也会被插入。虽然原因很正确,但它使得创建用户管理页面非常痛苦。

我的团队的Web应用程序使用Angular 7运行,目前只支持Chrome。但是很有可能我们需要支持其他浏览器,例如Internet Explorer、Edge、Firefox等。

我知道这是一个经常涉及的话题,并且我可以找到许多与这个问题类似的问题(像这样或者这样)。但是迄今为止我找到的每种解决方案都至少有一个很大的缺陷。

我在Chrome上尝试过的方法:

1) 使用autocomplete="new-password"

似乎Chrome/Chromium开发人员甚至忽略了type="password"的这个设置。

2) 使用type="text" autocomplete="new-password"和星号字体

这会禁用Chrome自动填充输入字段并隐藏字符。但是最大的缺陷在于该值仍然存在并且可以在不同字体家族中复制粘贴。输入字段也失去了type="password"的安全性,任何黑客都可以轻易获取该值。

3) 使用-webkit-text-security

这基本上与前面的解决方案相同,但这甚至不是CSS标准,只有少数浏览器支持它。

4) 用*替换值

这是我迄今为止尝试的最棘手的解决方案。当输入值更改时,我调用TypeScript中的一个函数:将新字符添加到本地字符串中,将DOM值更改为与字符数量相等的*,在(blur)时返回本地保存的值。

这给我留下了许多要处理的问题,包括:擦除字符串中的任何字符总是删除最后一个字符,除了最后一个问题之外,第一个字符始终保持不变,即使该值完全被删除,在字符串中知道要删除字符的位置。

这个解决方案不太理想。

5) 在浏览器设置中禁用域名密码管理

这真的不是解决问题的方法,因为这意味着我期望用户关闭域名密码管理。这也会导致不保存登录页面上的密码,因为许多用户可能需要。

6) 随机化[name][autocomplete]

通过单向绑定将值绑定到基于当前时间的随机字符串上,我可以确保密码字段与浏览器保存的任何字段都不匹配。虽然许多人报告说这在所有浏览器之间有效,但是当我使用chrome时,似乎根本不起作用。对我来说,只要输入为type="password",Chrome就会显示推荐密码。
已看到的解决方案:
1)使用两个输入字段
这对我来说似乎与我的解决方案4)相同,并且可能会带来麻烦。
2)使用jQuery禁用自动填充插件
这似乎非常接近我正在寻找的东西,但问题是它使用了jQuery。我所能说的就是,我们被告知我们不使用jQuery,并且我可能不能直接使用该插件。
我目前正在寻找一种使用angular实现此目的的方法,并且非常乐意得到任何帮助或指导。
如果您知道我没有提到的任何解决方案,请发表答案或在评论中留下链接。

我能做到的最好的方法是使用随机函数来设置自动完成和名称:结果类似于:autocomplete="mbshftbaqo" name="mbshftbaqo" 当页面重新渲染时,这当然会改变。 - vals
@vals 我已经成功地通过使用基于当前时间随机化的本地值来随机化自动完成和名称上的值:"this.rndName = String.fromCharCode(65 + Math.floor(Math.random() * 26)) + Date.now();" 但是没有任何反应。如果我忽略随机化名称和自动完成,并仅在密码字段上使用autocomplete="new-password"。它会禁用用户名和密码字段的自动填充,但仍会在我的表单中的密码字段上给出用户名/密码建议。有什么想法为什么会这样? - kebbaben
我认为只要所有常见浏览器都不支持 autocomplete="new-password",就不会有真正的解决方案。对我个人而言,我发现两个输入字段效果最好。我只是在我的布局中添加了一个捕获自动填充的隐藏字段 - 我同意这是一种 hacky 的方法,但我还没有遇到任何问题。 - Elias Johannes
@EliasJohannes 我试过使用隐藏字段,但当字段被隐藏时,Chrome 会自动找到最佳的替代方法。你能否提供一个可行的示例链接给我吗? - kebbaben
@kebbaben 在fiddle上并不能很好地展示,但这是我使用的代码:https://jsfiddle.net/EliasJohannes/wtz6v145/2/ 我在FF、Chrome和IE上测试过了,对我来说它是有效的(我还意识到我也在整个表单上设置了autocomplete)。 - Elias Johannes
2个回答

1
到目前为止,我发现的最好的解决方案是在密码字段上使用type="text",并在表单及其中的每个输入字段上使用autocomplete="off"
但是,由于仍然存在失去type="password"安全功能的重大缺陷,因此我不会将其标记为答案。文本字段还允许拼写检查,可以通过spellcheck="false"禁用。但是我已经阅读过,这可以通过浏览器设置来覆盖。
除非提出更好的解决方案,否则此问题将保持未回答状态。

0
对于任何感兴趣的人,我昨天遇到了这个问题并提供了以下解决方案:

function getCaretPosition() {
  if (window.getSelection && window.getSelection().getRangeAt) {
    let range = window.getSelection().getRangeAt(0);
    let selectedObj = window.getSelection();
    let rangeCount = 0;
    let childNodes = selectedObj.anchorNode.parentNode.childNodes;
    for (let i = 0; i < childNodes.length; i++) {
      if (childNodes[i] == selectedObj.anchorNode) {
        break;
      }
      if (childNodes[i].outerHTML)
        rangeCount += childNodes[i].outerHTML.length;
      else if (childNodes[i].nodeType == 3) {
        rangeCount += childNodes[i].innerText ? childNodes[i].innerText.length : 0;
      }
    }
    return range.startOffset + rangeCount;
  }
  return -1;
}

let secret_word_placeholder_elem = document.getElementById('secret_word_placeholder');
let secret_word_elem = document.getElementById('password');

secret_word_placeholder_elem.onkeypress = function(e) {

  let caretPosition = getCaretPosition();
  let entered_character = String.fromCharCode(e.key.charCodeAt(0));
  secret_word_elem.value = [secret_word_elem.value.slice(0, caretPosition), entered_character, secret_word_elem.value.slice(caretPosition)].join('');

  console.log("password: " + secret_word_elem.value);
}
#secret_word_placeholder {
  -webkit-text-security: disc;
  /* all styles below this line are optional */
  -webkit-appearance: textfield;
  background-color: white;
  -webkit-user-select: text;
  cursor: auto;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" />

<div class="form-group">

  <div class="row">

    <label class="col-md-3 text-right">Password:</label>

    <div class="col-md-9">
      <div contentEditable="true" style="height: auto;" class="form-control" id="secret_word_placeholder"></div>
      <input style="visibility: hidden; display: none" type="password" name="password" id="password" />
    </div>

  </div>
</div>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接