Chrome 自动填充/自动完成密码没有价值
Posted
技术标签:
【中文标题】Chrome 自动填充/自动完成密码没有价值【英文标题】:Chrome Autofill/Autocomplete no value for password 【发布时间】:2016-05-05 02:58:58 【问题描述】:当您为某个站点保存用户名和密码时,Chrome 会自动填充该用户名和密码,但如果您尝试获取密码输入字段的值,即使那里有值,它也是空字符串 ****** .
如果您单击页面上的某个位置,无论input type="password"
的值将被填充到哪里。
这是 html 结构的 Fiddle user/pass 和 console.log
命令。它在这里看不到,但可以在每个具有登录表单的页面上复制,并且用户名和密码在页面加载时自动填充。如果您在单击站点上的其他任何位置之前检查该字段的值,它将是空字符串。
在 Firefox 或 Internet Explorer 中情况并非如此,它将用密码填充 input
元素的值。
我使用的是 Windows 7 Ultimate 64 位操作系统,Google Chrome 版本是 48.0.2564.97 m
这是正常行为、错误还是?
更新:
如果您单击 F5 重新加载页面并检查密码字段,密码值将在那里。如果您单击 Chrome 左上角的重新加载按钮,则密码字段的值将为空字符串。
【问题讨论】:
正常行为,chrome中保存的密码只能通过settings->passwords访问,并且需要密码。如果密码可以被用户或javascript读取,将是一个安全问题。 不,不是,如果我在页面加载完成后单击某处,我可以使用开发工具检查input
元素并查看密码字段的值。
是的,您确实可以获取初始密码值,这很正常,但您无法获取用户输入的值。
我不知道您所说的“初始密码值”是什么意思,但如果我在加载该页面并检查 input type="password"
字段后为某个页面保存了用户/密码,我可以看到该值当您单击“保存此页面的密码”时,密码与从 Chrome 保存的密码相同。
我打开了一个问题,要求 Chromium 人员重新考虑这一点。如果您希望 Chrome 的行为与其他浏览器相同,请在此问题上加注星标。 bugs.chromium.org/p/chromium/issues/detail?id=669724
【参考方案1】:
这似乎是 Chrome 中的一个错误。当 Chrome 在初始页面加载(但不是刷新)时自动填充密码时,该值会出现在屏幕上的表单字段中,但在 Javascript 中查询 passwordField.value
会返回一个空字符串。如果您依赖于在 Javascript 中查看该值,这会阻止您这样做。一旦用户在页面上执行任何其他操作,例如单击页面上的任意位置,该值就会突然对 Javascript 可见。
我实际上并不能 100% 确定这是否是一个错误,或者这样做是否出于安全原因,例如通过欺骗浏览器填充密码来防止隐藏框架窃取您的密码。
我们使用的一种解决方法是检测 Chrome 对其已自动填充的字段所做的背景颜色更改。 Chrome 将自动填充字段的背景颜色为黄色,即使该值不可见,Javascript 也始终可以看到此更改。在 Javascript 中检测到这一点让我们知道该字段已自动填充了一个值,即使我们在 Javascript 中看到该值是空白的。在我们的例子中,我们有一个登录表单,其中在您在密码字段中填写某些内容之前不会启用提交按钮,并且检测一个值或自动填充背景颜色足以确定该字段中有内容.然后我们可以启用提交按钮,然后单击按钮(或按 Enter)立即使密码字段值对 Javascript 可见,因为与页面交互解决了问题,因此我们可以从那里正常进行。
【讨论】:
嗨,亚当。我想出了一种触发 Chrome 将值视为真实值的方法,以便可以访问.value
,并将其添加为答案。这个错误没有修复,但至少有一个解决方案。
自动填充最多需要多长时间?我注意到即使是 300 毫秒也不够用……
我不知道自动填充可以花费的最长时间,特别是如果用户有一个渲染阻止浏览器扩展或中断页面加载的东西,它的字段是动态的使用脚本注入页面。当自动填充不知道该怎么做时,用户也可能从自动填充中手动选择,例如从“其他密码”对话框中选择。我通过使用 setInterval 轮询字段来处理这个问题,这样我就可以快速响应,但也可以随着时间的推移进行监控。
@AdamHamilton 您好,我遇到了这个问题,我认为我们可以模拟一个 click/keyup 事件来模拟“点击页面上的任意位置”,以使该值对 javascript 可见。你试过这个吗?
我试过了,但我自己没有运气。我怀疑浏览器正试图专门阻止它,因为它可能试图通过将密码填充到您不与之交互的框架中来防止泄露密码。因此,如果我的理论是正确的,它正在寻找一种实际的用户驱动交互。可能我只是没有尝试正确的方法,但我确实通过了。【参考方案2】:
我已经找到了解决这个问题的方法,至少可以满足我的目的。
我有一个登录表单,我只想在它加载后立即按 Enter,但我在 Chrome 中遇到了密码空白问题。
以下似乎有效,允许初始输入键失败并在 Chrome 唤醒并提供密码值后重试。
$(function()
// bind form submit loginOnSubmit
$('#loginForm').submit(loginOnSubmit);
// submit form when enter pressed on username or password inputs
$('#username,#password').keydown(function(e)
if (e.keyCode == 13)
$('#loginForm').submit(e);
return false;
);
);
function loginOnSubmit(e, passwordRetry)
// on submit check if password is blank, if so run this again in 100 milliseconds
// passwordRetry flag prevents an infinite loop
if(password.value == "" && passwordRetry != true)
setTimeout(function()loginOnSubmit(e,true);,100);
return false;
// login logic here
【讨论】:
【参考方案3】:截至 2016 年 7 月 8 日的工作答案
Adam correctly stated 这是一个错误(或预期行为)。但是,之前的答案都没有真正说明如何解决这个问题,所以这里有一种方法可以强制 Chrome 将自动完成的值视为真实值。
有几件事情需要按顺序发生,而这只需要在 Chrome 而不是 Firefox 中运行,因此if
。
首先我们关注元素。然后我们创建一个新的TextEvent
,并运行initTextEvent
,它将我们指定的自定义字符串(我使用“@@@@@”)添加到值的开头。这会触发 Chrome 实际开始表现得就像值是真实的一样。然后我们可以删除我们添加的自定义字符串,然后我们取消焦点。
代码:
input.focus();
var event = document.createEvent('TextEvent');
if ( event.initTextEvent )
event.initTextEvent('textInput', true, true, window, '@@@@@');
input.dispatchEvent(event);
input.value = input.value.replace('@@@@@','');
input.blur();
2016 年 8 月 10 日编辑
这目前仅适用于 Windows 和 android 上的 Chrome。不适用于 OSX。此外,它将于 2016 年 9 月完全停止工作,根据:
https://www.chromestatus.com/features/5718803933560832
另外,我已经开了一张 Chromium 票。
https://bugs.chromium.org/p/chromium/issues/detail?id=636425
截至 8 月 12 日,Chrome 团队的一名成员在上述票证上表示,该行为不会改变,因为他们不认为这是一个错误。
长期变通建议:
也就是说,当前的行为在首次实施时已经过调整。用户不再需要与要报告的值的密码输入进行交互。用户现在只需要与页面的任何部分进行交互(发送鼠标或键盘事件)。这意味着虽然在页面加载上运行验证仍然不起作用,但单击提交按钮将导致 Chrome 正确报告密码值。然后,解决方法是在提交时重新验证所有可能自动完成的输入(如果这是您想要做的)。
2016 年 12 月 13 日编辑:
一张新的 Chromium 票已打开,并且收到更好。如果有兴趣改变 Chrome 的这种行为,请给这张新票加注星标:
https://bugs.chromium.org/p/chromium/issues/detail?id=669724
【讨论】:
【参考方案4】:Adam 指定的解决方法:
... 检测 Chrome 对其已自动填充的字段所做的背景颜色更改。 Chrome 将自动填充字段的背景颜色为黄色,即使值不可见,Javascript 也始终可以看到此更改。在 Javascript 中检测到这一点让我们知道该字段已自动填充了一个值,即使我们在 Javascript 中看到该值是空白
我确实喜欢这样:-
getComputedStyle(element).backgroundColor === "rgb(250, 255, 189)"
其中 rgb(250, 255, 189) 是黄色 Chrome 适用于自动填充输入。
【讨论】:
【参考方案5】:对于 Angular,Chrome 中的新行为(仅允许在用户与页面交互后读取自动填充的值)在某些情况下(例如,使用标准方法)使用 Angular 的验证功能时会出现问题/action 表单上的属性)。由于提交处理程序会立即执行,因此它不允许表单验证器从 Chrome 捕获自动填充的值。
我为此找到了一个解决方案,即在提交处理程序中显式调用表单控制器 $commitViewValue
函数以在检查 form.$valid
或 form.invalid
等之前触发重新验证。
例子:
function submit ($event)
// Allow model to be updated by Chrome autofill
// @see http://***.com/questions/35049555/chrome-autofill-autocomplete-no-value-for-password
$scope.loginModule.$commitViewValue();
if ($scope.loginModule.$invalid)
// Disallow login
$scope.loginModule.$submitted = true;
$event.preventDefault();
else
// Allow login
虽然到目前为止这对我们有用,但如果有人找到另一个更优雅的解决方法来解决这个问题,我会非常感兴趣。
【讨论】:
【参考方案6】:Chrome 的预期行为是自动填充密码在 DOM 中有一个空的 value
,直到用户以某种方式与框架交互,此时 chrome 实际填充了该值。在此之前,任何客户端验证或尝试 ajax 提交表单都会看到密码为空。
此“在框架交互时填充密码值”行为不一致。我发现当表单托管在同源 iframe 中时,它只会在第一次加载时运行,而不会在后续加载时运行。
这在 ajax 表单上最为明显,其中自动完成密码在首次加载时填充,但是如果该密码无效并且 ajax 提交重新呈现表单 DOM,则自动完成密码重新出现在视觉上,但 value
永远不会填充,与交互无关。
提到的解决方法(例如触发blur
或input
事件)在这种情况下均无效。我发现的唯一解决方法是在 ajax 进程重新呈现表单后重置密码字段值,例如:
$('input[type="password"]').val("");
在上述操作之后,Chrome 实际上再次自动完成密码,但实际上填充了 value
。
在我当前的用例中,我使用 ASP.NET 的 Ajax.BeginForm 并在 AjaxOptions.OnSuccess 回调中使用上述解决方法。
【讨论】:
【参考方案7】:继续Andy Mercer said,这是我的工作。像很多人一样,我不需要实际的密码值。我真的只需要知道密码框已被自动填充,以便我可以显示正确的验证消息。
就个人而言,我不会使用建议的解决方案来检测 Chrome 自动填充导致的背景颜色变化。这种方法似乎很脆弱。这取决于那永不改变的黄色。但这可以通过扩展来改变,并且在另一个基于 Blink 的浏览器(即 Opera)中会有所不同。另外,谷歌不保证将来不会使用不同的颜色。无论风格如何,我的方法都有效。
首先,在 CSS 中,当 -webkit-autofil
伪类应用于 INPUT
时,我设置了它的内容:
input:-webkit-autofill
content: "\feff"
然后,我创建了一个例程来检查要设置的内容:
const autofillContent = `"$String.fromCharCode(0xFEFF)"`;
function checkAutofill(input)
if (!input.value)
const style = window.getComputedStyle(input);
if (style.content !== autofillContent)
return false;
//the autofill was detected
input.classList.add('valid'); //replace this. do want you want to the input
return true;
最后,我轮询了input
以允许自动填充时间完成:
const input = document.querySelector("input[type=password]");
if (!checkAutofill(input))
let interval = 0;
const intervalId = setInterval(() =>
if (checkAutofill(input) || interval++ >= 20)
clearInterval(intervalId);
, 100);
【讨论】:
我使用了类似的方法,有一个间隔,因为我发现单个超时并不总是被触发,如果没有必要,我不想等待 2 秒。但是,我没有设置内容,而是使用document.querySelectorAll('input[type=\"password\"]:-webkit-autofill')
简单地检查密码字段上是否存在 webkit 自动填充元素。我每 100 毫秒检查一次,如果找到或者如果 2 秒过去了,我会取消间隔。似乎是我尝试过的最强大的解决方案。【参考方案8】:
12 月 16 日/Chrome 54 的另一个选项
我无法获取密码字段的值,但是,“一会儿”后,我可以通过选择它来获取密码的长度,这足以让我启用提交按钮。
setTimeout(function()
// get the password field
var pwd = document.getElementById('pwd');
pwd.focus();
pwd.select();
var noChars = pwd.selectionEnd;
// move focus to username field for first-time visitors
document.getElementById('username').focus()
if (noChars > 0)
document.getElementById('loginBtn').disabled = false;
, 100);
【讨论】:
实际上,由于似乎是时间问题,这似乎只是偶尔起作用。有时报告的noChars
为 0,有时为正值。我不得不将超时时间增加到 200 毫秒,以便它或多或少一致地工作。【参考方案9】:
var txtInput = $(sTxt);
txtInput.focus();
txtInput.select();
此解决方案适用于我的情况。 使用 jQuery 3.1.1。
【讨论】:
【参考方案10】:刚刚写了一个与此相关的角度指令。最终得到以下代码:
if ('password' == $attrs.type)
const _interval = $interval(() => //interval required, chrome takes some time to autofill
if ($element.is(':-webkit-autofill')) //jQuery.is()
//your code
$interval.cancel(_interval);
, 500, 10); //0.5s, 10 times
ps:它不会检测到 100% 的时间,chrome 可能需要超过 5 秒才能填充输入。
【讨论】:
【参考方案11】:这是我对这个问题的解决方案:
$(document).ready(function()
if ( $("input:-webkit-autofill").length )
$(".error").text("Chrome autofill detected. Please click anywhere.");
);
$(document).click(function()
$(".error").text("");
);
基本上,点击会使输入对用户可见,所以我要求用户点击,当他们点击时,我会隐藏消息。
不是最优雅的解决方案,但可能是最快的。
$(document).ready
不等待浏览器自动填充,应该替换为
$(window).on("load", checkforAutoFill())
【讨论】:
【参考方案12】:这不是错误。这是一个安全问题。想象一下,如果一个人可以在没有用户确认的情况下使用 javascript 来检索自动填充的密码。
【讨论】:
【参考方案13】:$element.is("*:-webkit-autofill")
为我工作
【讨论】:
【参考方案14】:如果您想让输入被视为已完成,请尝试在其上触发blur
:
$('input[type="password"]').blur();
【讨论】:
【参考方案15】:自动完成功能已成功禁用。 有效!
[HTML]
<div id="login_screen" style="min-height: 45px;">
<input id="password_1" type="text" name="password">
</div>
[JQuery]
$("#login_screen").on('keyup keydown mousedown', '#password_1', function (e)
let elem = $(this);
if (elem.val().length > 0 && elem.attr("type") === "text")
elem.attr("type", "password");
else
setTimeout(function ()
if (elem.val().length === 0)
elem.attr("type", "text");
elem.hide();
setTimeout(function ()
elem.show().focus();
, 1);
, 1);
if (elem.val() === "" && e.type === "mousedown")
elem.hide();
setTimeout(function ()
elem.show().focus();
, 1);
);
【讨论】:
【参考方案16】:只需将用户名字段的自动完成属性设置为用户名,密码字段设置为新密码即可;
<input type="text" id="username" autocomplete="username">
<input type="password" id="password" autocomplete="new-password" >
【讨论】:
【参考方案17】:对我来说,这些解决方案似乎都不起作用。
我认为值得一提的是,如果你想将它用于 CSS 样式,你应该使用 -webkit-autofill 属性,如下所示:
input:-webkit-autofill~.label,
input:-webkit-autofill:hover~.label,
input:-webkit-autofill:focus~.label
input:focus~.label,
input:not(.empty)~.label
top: -12px;
font-size: 12px;
color: rgba(0, 0, 0, .4);
font-weight: 600
【讨论】:
【参考方案18】:你提到:
如果你点击页面上的某个地方,无论输入 type="password" 的值在哪里填写。
这就是为什么我只是简单地使用$('body').click();
来模拟第一次点击,然后该值在 JavaScript 中可用。
另外,我在我的注册表单密码字段中设置了autocomplete="new-password"
,这样该字段就不会自动填充,用户必须填写新密码。
更多信息请参见this Google Developers page。
【讨论】:
【参考方案19】:我的解决方案将我的 css 与 chrome 自动完成颜色进行比较...
$('input, select, textarea').each(function()
var inputValue = $(this).val();
if ( inputValue != "" || $(this).css("background-color") != "rgba(255, 255, 255, 0)")
$(this).parents('.form-group').addClass('focused');
);
【讨论】:
【参考方案20】:我尝试了所有解决方案,但都没有为我工作,所以我想出了这个。 我的问题是我有一个输入可以在填充占位符顶部时移动它,当然这在 Chrome 自动填充时不起作用。 仅在 Chrome 中测试:
setTimeout(function ()
var autofilled = document.querySelectorAll('input:-webkit-autofill');
for (var i = 0; i < autofilled.length; i++)
Do something with your input autofilled
, 200);
【讨论】:
【参考方案21】:令人惊讶的是,在 2021 年,Chrome 尚未解决此问题,自 2014 年以来我一直遇到自动完成问题,但仍然没有。
Chrome 的自动完成功能会误导用户,我不知道他们想要实现什么但看起来不太好。
就像现在一样,表单出现向用户显示自动完成的文本(用户/电子邮件/密码),但在后台 html 中 - 值不在元素内。 由于值不在字段中,自定义验证将禁用提交按钮。
检查字段值的脚本会说 value 为 null,这对用户来说更加混乱,因为她/他可以看到文本在那里,并且可以假设它是有效的,从而导致混淆 delete-one 插入一个字符。 (尴尬的是,我不得不承认我不知道你需要点击HTML的正文,所以我不知道有多少用户不知道)
在我的情况下,我希望始终有空白字段,然后发现它只是不必要地花费时间来使其工作。
如果我们尝试autocomplete=off
,我们会发现它不起作用。为了验证字段并让我们说启用按钮,我们需要做一些诡计。
(请记住,我已经尝试过 autocomplete=password
new-password)和来自 official resource 的其他类型的 Hocus-Pocus 诡计。
最后我做到了。
<script>
$('#user').value = ' '; //one space
$('#pass').value = ' '; // one space - if this is empty/null it will autopopulate regardless of on load event
window.addEventListener('load', () =>
$('#user').value = ''; // empty string
$('#pass').value = ''; // empty string
);
</script>
因此,在某些情况下,它会在密码字段中闪烁片刻,*
不理想但:/ ...
【讨论】:
【参考方案22】:我的版本是 95.0.4638.69
我遇到了类似的问题,我通过将表单的名称从“login-form”更改为另一个没有任何意义的名称来解决它并解决它。我没有删除 name 属性的原因是因为如果我删除 name 属性 Chrome 会查找 id 属性并做同样的事情。
【讨论】:
以上是关于Chrome 自动填充/自动完成密码没有价值的主要内容,如果未能解决你的问题,请参考以下文章