2019,Chrome76,关闭自动完成的方法

2019, Chrome 76, approach to autocomplete off

关于这个的帖子很少。您花费数小时浏览每个答案、测试、阅读评论,发现没有解决方案。 Chrome76,2019年你做了什么有用的?

autocomplete='nope'

这是 Chrome 76 的当前工作解决方案。

更新,2020 年 1 月: 从 Chrome 79 开始,自动完成(如此处定义)不再将 autocomplete="some-unrecognised-value" 视为等于 autocomplete="on",所以 autocomplete="nope" 或类似的东西现在可以有效地禁用自动完成和自动填充。

2020 年 4 月更新: 他们又改了。从 Chrome 81 开始,autocomplete="some-unrecognised-value" 不再有效地禁用自动完成机制。然而,自动填充现在似乎比以前保守得多——它仍然不符合规范(带有 name="email"autocomplete="off" 的字段仍然会收到自动填充建议)但它不会在随机表单字段上提供虚假地址片段。因此,我现在的建议是使用 autocomplete="off"。如果您想在名为 email 的字段上执行此操作,那么您可能运气不好:-(


TL,DR: autocomplete 属性似乎没有设置可以可靠地关闭所有自动完成下拉菜单。然而,导致这种情况的情况非常复杂,值得记录,以期消除大量相互矛盾的建议...

Chrome 的当前 (76.0.3809.132) 版本中存在两种截然不同的机制,我们将其称为自动填充和自动完成(不一定是它们的官方名称):

自动填充

自动填充功能会尝试使用存储在浏览器设置中的地址信息来填写表单。它可以通过下拉列表底部的 "Manage addresses..." 选项(或类似选项)来识别。此功能不支持 autocomplete="off"autocomplete="false",这是 Chrome 开发人员的慎重决定。

a statement outlining this decision 中,zkoch 提供了这个解决方法:

In cases where you really want to disable autofill, our suggestion at this point is to utilize the autocomplete attribute to give valid, semantic meaning to your fields. If we encounter an autocomplete attribute that we don't recognize, we won't try and fill it.

As an example, if you have an address input field in your CRM tool that you don't want Chrome to Autofill, you can give it semantic meaning that makes sense relative to what you're asking for: e.g. autocomplete="new-user-street-address". If Chrome encounters that, it won't try and autofill the field.

这是autocomplete="nope"等尝试解决方案的基础;自动填充机制将跳过任何具有它无法识别的 autocomplete 属性值的字段。

执行此决定的代码,备案:https://chromium.googlesource.com/chromium/src/+/refs/tags/78.0.3903.1/components/autofill/core/browser/form_structure.cc#1218

自动完成

自动完成功能提供了以前从此表单域提交的值的下拉列表。此下拉列表没有 "Manage addresses..." 选项。自动完成 遵守 autocomplete="off"autocomplete="false" 属性;任何其他值(包括 'invalid' 值,例如 autocomplete="nope")将保持启用状态。

结论

无法通过 autocomplete 下拉菜单关闭自动完成下拉菜单;任何禁用自动填充的值都会使自动完成保持启用状态,反之亦然。任何认为他们已经找到可行解决方案(通过 autocomplete 或其他方法,例如 CSS 黑客)的人应该检查它是否适用于 both 机制。

不幸的是,要说服 Chrome 的开发人员这已被破坏可能会是一场艰苦的斗争。 Autofill 的开发者显然相信他们做出了一个经过深思熟虑的决定来打破 autocomplete="off",同时为网络开发者提供了一个替代方案;由于比他们意识到的更微妙的原因,这种替代方案被打破了。从他们的角度来看,由此产生的 howls of protest 来自心怀不满的开发人员,他们懒得跳过一个小圈并更新他们的 autocomplete="off" 属性。在所有的噪音中,消息没有传递:箍坏了。

正如 所解释的那样,必须禁用 autofillautocomplete 功能,这在单个输入上似乎是不可能的。
我发现的唯一可行的解​​决方案是在输入上设置 autocomplete="off" 并在愚弄 autofill 的真实输入之前添加隐藏的假输入,如下所示:

<input name="Fake_Username" id="Fake_Username" type="text" style="display:none">
<input name="Fake_Password" id="Fake_Password" type="password" style="display:none">
<input name="NameInput" id="NameInput" type="text" autocomplete="off">

* 这个答案不正确。我已经发布了一个更好(但更丑陋)的解决方案作为新答案并保留了这个答案,因为某些部分可能仍然有用。如果这不是处理 Whosebug 上错误答案的方法,请随时删除这个 *

考虑使用 autocomplete=,其中 在每个字段和整个页面加载中都是唯一的。

例如某个字段是在时间戳TS请求页面后创建的第N个字段,其可以选择nope__

对自动完成的影响:由于 是自动完成的自定义值,chromium 不会激活自动完成功能(参见 form_structure.cc)。

对自动填充的影响:chromium 通过将其指纹与之前遇到的字段的指纹进行比较来识别字段(参见 form_field_data.cc)。如果被识别,它可能会提供一个记忆值列表。指纹包含自动完成属性的值。由于没有两个 nonce 是相等的,因此没有字段被识别。

备注:

  • 与 gasman 的回复相比,此处使用的术语自动完成和自动填充已互换。

  • 所有字段都应在客户端动态创建(除非您愿意不缓存页面)。

禁用自动填充: 将自动完成属性设置为非标准值,例如"nope".

禁用自动完成: 提交表单时,自动完成功能会存储字段名称及其值。 除了将自动完成设置为 "off"/"false"(参见 why)之外,(几乎,参见注释 1)没有什么明智的做法可以防止存储。 不幸的是,这不是一个选项,因为它会启用自动填充。

但是,可以通过将“!”附加到字段名称来防止检索以前的值,其中 在每次页面加载时都是唯一的 (从而使字段名称无法识别)。

在客户端,这可以通过类似以下行的方式实现 javascript(在页面加载时):

Array.prototype.slice.call(document.body.getElementsByTagName('INPUT'))
   .forEach(function(elt) { elt.name += '!' + new Date().getTime(); });

在服务器端以“!”开头的部分(如果有的话)应该从变量名中删除(收到 post 个变量)。

PS:这个答案是对我之前的解决方案的勘误,该解决方案更清洁但未经过充分测试,并且 - 正如加斯曼正确指出的那样 - 不适用于普通表格。这个新解决方案在 Chrome Canary 79 上进行了测试,确实有效,影响相对较小并且降级很好。尽管如此,我还是对发布这个 hack 感到内疚,如果我以真实的形式遇到它,我会感到更加内疚。它*非常*脏。

注意 1:防止 有意义的存储的唯一方法是首先不设置 name 属性(或取消设置),这需要拦截将事件提交给 post 数据 "manually"(使用 XMLHttpRequest)。由于问题是关于表单的,并且此策略绕过了传统的表单机制,因此我没有详细说明该方法。不过这是一个更好的解决方案。


附录:我决定跟进注释 1,因为我真的不喜欢非本地化的解决方案。这是 vanilla JS 的本地化版本,它将所有影响限制在客户端的单个位置。将其作为脚本附加到文档主体或将其放入文档的 onload 处理程序中。

function disableInputSuggestions(form) { // note: code uses ECMA5 features 
    // tweak the inputs of form 
    var inputs = Array.prototype.slice.call(form.getElementsByTagName('INPUT'));
    var nonce = Date.now();
    inputs.forEach(function(input, i) { 
        input.autocomplete = 'nope'; // prevent autocomplete
        input.originalName = input.name || input.id; // to not let this code break form handling of inputs without names (browsers fallback to the id in that case)
        input.name = nonce + '_' + i; // prevent autofill (if you're willing to eliminate all input ids first, then clear the name instead)
    });
    // replace the default submit handler by a custom one 
    form.onsubmit = function(ev) {
        // get the form data using the original variable names
        var formData = new FormData();
        inputs.forEach(function(input) { formData.set(input.originalName, input.value); });
        // submit the form data using XMLHttpRequest (alternatively, use a helper form or temporarily undo the tweaks to form) 
        var submitter = new XMLHttpRequest();
        submitter.open(form.getAttribute('method'), form.getAttribute('action'));
        submitter.onreadystatechange = function() {
            if(submitter.readyState == 4 && submitter.status == 200) {
                // handle the server response, here assuming the default form.target = "_self"  
                document.open();
                document.write(submitter.responseText);
                document.close();
            }
        }
        submitter.send(formData);
        return false; // prevent submitting form
    }; 
}
disableInputSuggestions(document.forms.myForm); // assumed: the form has id = myForm

尝试在您的输入字段中使用 type="search" 而不是 "text",我已经这样做了好几次并且对我有用。

截至 2019 年 12 月 6 日,Chrome v78.x

autocomplete="off" 这样的标准方法现在几乎可以用于最新版本的 Chrome。除了这个:

这件事真是令人失望,因为它不仅不尊重 "nope" 等 standard/non-standard 值,而且实际上没有办法关闭它,除非输入与 “地址” 条款。

我们究竟如何在不使用与地址相关的词的情况下显示与地址相关的输入字段? 有史以来最简单的解决方案来了。

  • 确保输入元素的 nameid 不包含任何与地址相关的术语。 id="input-street"name="destination-zip" 之类的属性是大禁忌。

  • 这是最关键的部分:如果您需要为文本输入或其任何相邻元素使用任何人类可读的地址术语,在上述术语的字母之间插入“隐形”零宽度连接符 (&zwnj;)。通过这种方式,我们可以欺骗 Chrome 的 AI 功能并绕过其严格的自动完成行为。

一些工作示例:

<input id="input-stret" placeholder="S&zwnj;treet" autocomplete="off">

<form action="/action_page.php">
  <label for="product-addres">Product A&zwnj;ddress</label>
  <input name="addres" id="product-addres" autocomplete="off">
</form>

好了。不再有烦人的地址管理菜单,也没有任何常规的自动完成菜单。

Chrome 版本 81.

对我来说,当输入类型是 TEL、EMAIL 或 SEARCH 时,它可以使用自动完成='disabled'。 当输入类型为 NUMBER 时,它适用于 autocomplete='off'.

但是当输入类型是 TEXT .. 它可能适用于 autocomplete='off'。如果没有,它将使用 autocomplete='disabled'.

你可以试试这个,也许它对你有用(对我来说它在 95% 的情况下都有效):

// Désactivation de l'autocomplete des input text
function setAutocomplete(val) {
    var E = document.getElementsByTagName('INPUT');
    for (var i = 0 ; i < E.length ; i++) {
        if (E[i].name == 'txt_nom') { console.log('txt_nom', E[i]); }
        var type = E[i].type.toUpperCase();
        if (E[i].autocomplete != '') { continue; }
        if (type == 'HIDDEN') {
            //
        } else if (type == 'NUMBER') {
            E[i].autocomplete = 'off';
        } else if ((type == 'TEL') || (type == 'EMAIL') || (type == 'SEARCH')) {
            E[i].autocomplete = 'disabled';
        } else {
            E[i].autocomplete = val;
        }
    }
}

// Exécution de diverses fonctions à la fin de chaque chargement
window.addEventListener("load", function() {
    // Désactivation de l'autocomplete des input text
    setAutocomplete('off');
});

试试这个,我用了这个小技巧,直到现在(2020 年 9 月)一直有效。我希望这对很多人有用

--HTML--
<input type="text" name="example" autocomplete="off">
    
--Javascript--
let elements = document.querySelectorAll('[autocomplete="off"]');
elements.forEach(element => {
    element.setAttribute("readonly", "readonly");
    element.style.backgroundColor = "inherit";
    setTimeout(() => {
        element.removeAttribute("readonly");
    }, 500);
})

在Chrome91

您需要使用随机值,这意味着每次加载页面时该值都会发生变化。

从我所做的测试来看,chrome 似乎能记住它已经遇到的任何属性值,并会在下次为该属性值建议最后一次看到的值。所以,如果你输入 autocomplete="nope",chrome 会记住 autocomplete="nope" 等于你输入的最后一个值 autocomplete="nope"。

通过使用 chrome 从未见过的唯一随机值,它不会提出任何建议,因为它从未见过该值。

PHP 7 例子

<input type="text" name="firstname" autocomplete="<?= bin2hex(random_bytes(10)) ?>" />

限制

它似乎对地址字段有效,但对登录字段无效。我还没有测试过信用卡字段。

我做了一个小 jQuery 插件,可以禁用任何浏览器的任何类型的自动完成功能

用于表单标签,参数少,可与其他jQuery方法嵌套。

$('#login_form').randomizeFormFields();

它改变了这个:

<form id="login_form" action="" method="post">
  <input type="text" name="email">
  <input type="password" name="secret">
</form>

进入这个:

<form id="login_form" action="" method="post">
  <input type="text" name="yQoiFZkCrzwWXN3WWgM8Jblby">
  <input type="password" name="ono1qamA9CzrH4tW2COoRtFKI">
</form>

提交后保留原始名称

// returned post (php example)
array(2) {
  ["email"]=>
  string(16) "email@domain.com"
  ["secret"]=>
  string(19) "supersecretpassword"
}

https://github.com/cicerogeorge/randomize-form-fields

有想法请fork一下

我已经尝试对 html 表单中的 EmailId 文本框使用 autocomplete = "off" 和 autocomplete = "nope",但它不适用于 Google Chrome。所以我尝试了以下对我有用的更改。

<input type="email" class="tbx-input" name="Email" style="display:none;">

<input type="email" class="tbx-input" name="Email" id="Email" placeholder=" " required autocomplete="nope">

我无法让这些建议中的任何一个发挥作用...所以我只是将我的输入设置为文本区域,设置为 cols="1" 并禁用调整 space。