如何在不需要用户交互的情况下自动填写密码字段?

如何在不需要用户交互的情况下自动填写密码字段?

问题描述:

如果我从Tampermonkey脚本中检查了<input type="password"/>并使用change处理程序观察了由Chrome的密码管理器功能填充的密码字段的更改,则该值将一直为空,直到我实际执行一次实际点击这一页.我已经尝试过在页面中单击脚本,但是Chrome知道这不是真正的点击.当我物理单击页面时,change事件突然触发,密码字段获取一个值,然后我的脚本正确响应(由于发生了change事件).但是我写这个脚本的目的是避免首先与页面交互,所以这违背了我的脚本的重点.

If I inspect an <input type="password"/> from my Tampermonkey script and observe changes using a change handler for a password field that is filled by the Password Manager feature of Chrome, the value remains empty until I physically perform a real click in the page. I have tried in my script clicking in the page, but Chrome knows it’s not a real click. When I physically click in the page, the change event suddenly fires, the password field gets a value, and then my script reacts properly (due to having the change event). But I wrote this script to avoid having to interact with the page in the first place, so this defeats the point of my script.

是否有一种方法可以使TamperMonkey将该页面标记为已与用户进行了交互(例如,某些假设的GM_setUserTouched()GM_autoFillPasswords() API),以便密码管理器功能实际上填充了<input type="password"/>而没有需要我单击页面?

Is there a way to get TamperMonkey to mark the page as having had the user interact with it (e.g., some hypothetical GM_setUserTouched() or GM_autoFillPasswords() API) so that the Password Manager feature actually fills the <input type="password"/> in without requiring me to click in the page?

在Chrome中,此行为记录在#352527注释中15对报告者而言是意外行为#398805在某些情况下,Chrome无法实现我不想要的行为.自动填充功能和Chrome内置的密码管理器填写表单后,会在密码字段中向用户显示密码字符,但DOM HTMLInputElement.value设置为"".当用户与页面互动时(例如通过单击页面或按下键),Chrome会修改HTMLInputElement.value以包含密码,并在该元素上触发change事件.引用的这样做的原因是安全性原因"(例如,如果网站脚本正在从密码元素中读取,则只有当用户正在查看页面时,才有机会这样做……所以弹出框或不可见框架我不确定这能为您提供什么保护:一旦用户与页面进行交互,无论如何,所有脚本都将有权访问密码.由于与<input type="password"/>来自同一来源,因此网站本身具有安全漏洞,而不是Chrome…).

In Chrome, this behavior is documented in #352527 comment 15 where it is unexpected behavior to the reporter and #398805 where there is a case that Chrome fails to implement the behavior I don’t want. It is considered a feature that when autofill and Chrome’s built-in Password Manager fill out a form, password characters are displayed to the user in the password field, but the DOM HTMLInputElement.value is set to "". When the user interacts with the page, such as by clicking in it or pressing a key, Chrome modifies HTMLInputElement.value to contain the password and a change event is fired at the element. The cited reason for doing this is "security reasons" (e.g., if a website script was reading from the password element, it only would have a chance to do so if the user was looking at the page… so popunders or non-visible frames wouldn’t be able to do it or something? I’m not sure what this protects you from: once the user interacts with the page, all of the scripts would have access to the password anyway. And if bad scripts are being served from the same origin as the <input type="password"/>, the website itself has a security flaw, not Chrome…).

Greasemonkey历史上具有助手API @grant系统,以使用户脚本能够正常工作围绕这样的问题.在创建repro(如下)时,我发现Firefox使自动填充密码可用于DOM,而无需等待用户与窗口交互.因此,Greasemonkey不需要GM_forceAutofill() API,因为Firefox不会显示此Chrome怪癖.结果,Tampermonkey没有这样的API.

Greasemonkey historically has helper APIs and a @grant system to enable the userscript to work around issues like this. when creating the repro (below), I discovered that Firefox makes the autofill password available to the DOM without waiting for the user to interact with the window. Thus, Greasemonkey doesn’t need a GM_forceAutofill() API because Firefox doesn’t exhibit this Chrome quirk. As a result, Tampermonkey doesn’t have such an API.

由于当我描述Chrome表现出的行为时人们不相信我,因此我准备了一个复制品.要使Chrome进入认为用户尚未与页面进行交互的状态,需要付出一些努力,但是使用这些步骤,您应该能够看到我看到的内容:

Because people do not believe me when I describe the behavior exhibited by Chrome, I have prepared a repro. It takes some work to get Chrome into a state where it doesn’t think the user has interacted with the page yet, but you should be able to see what I see using these steps:

  1. 打开Chrome.我正在Windows 10上使用64位Chrome 61.0.3163.91.
  2. 导航到 https://fiddle.jshell.net/xqfynp3e/22/显示/灯光/
  3. 输入一些虚假的用户名和密码,然后按Enter或单击按钮. Chrome浏览器应提示您保存密码.
  4. 保存密码.
  5. 打开开发人员工具.
  6. 将此输入到控制台(以导航至页面而不会意外交互):window.location.href = 'https://fiddle.jshell.net/xqfynp3e/22/show/light/?1'
  7. 在控制台中运行document.querySelector('input[type=password]').value.
  8. 观察到表单的密码出现可以直观地看到并阅读Console中的DOM元素会生成"" .
  9. 单击文档.
  10. 再次在控制台中运行document.querySelector('input[type=password]').value.
  11. 观察到表单的密码未更改外观,但在Console中读取DOM元素却产生了错误您保存的密码.
  1. Open Chrome. I am using Chrome 61.0.3163.91 64-bit on Windows 10.
  2. Navigate to https://fiddle.jshell.net/xqfynp3e/22/show/light/
  3. Enter some bogus username and password and hit enter or click the button. Chrome should prompt you to save the password.
  4. Save the password.
  5. Open Developer tools.
  6. Enter this into Console (to navigate to the page without accidentally interacting with it): window.location.href = 'https://fiddle.jshell.net/xqfynp3e/22/show/light/?1'
  7. Run document.querySelector('input[type=password]').value in Console.
  8. Observe that the form’s password appears to be filled in visually and yet reading the DOM element in Console yields "".
  9. Click in the document.
  10. Run document.querySelector('input[type=password]').value in Console again.
  11. Observe that the form’s password hasn’t changed appearance and yet reading the DOM element in Console yields the bogus password you saved.

我的问题已重申:如何使Tampermonkey执行单击文档"步骤?如何告知Chrome的密码自动填充程序,我与该页面进行了互动,而实际上并未与该页面进行实际互动?

My question, restated: how can I get Tampermonkey to perform the "Click in the document" step? How do I tell Chrome’s password auto-filler that I interacted with the page without actually physically interacting with the page?

我找到了另一种方法来安全地将密码存储在Chrome中,并使用凭据Web API的静默中介支持通过用户脚本访问它们: https://imgur.com/a/ts2W1

I have found an alternative way to securely store passwords in Chrome and access them via userscripts by using the Credentials Web API’s silent mediation support: https://imgur.com/a/ts2W1

您不能使用Google的内置密码存储来执行此操作,因为正如您自己说的那样, Chrome需要用户交互才能启用此类密码 -作为安全功能.

You cannot do this using Google's built-in password storage because, as you stated yourself, Chrome requires user interaction to enable such passwords -- as a security feature.

具体来说,Chrome需要将isTrusted属性设置为true的事件. Tampermonkey无法解决此问题,因为 甚至是Chrome扩展程序无法设置isTrusted属性 .

Specifically, Chrome requires an event with the isTrusted property set to true. Tampermonkey cannot work around this because even Chrome extensions are not able to set the isTrusted property.

另请参见,与此相关的功能请求从2015年起.

See also, this related feature request from 2015.

一种解决方案是使用密码管理器填写这些字段,而无需使用Google的内置存储.
有很多可用的,具有不同程度的跨设备和跨浏览器支持.

One solution is to use a password manager that fills these fields without using Google's built-in storage.
There are many available, with varying degrees of cross-device, and cross-browser, support.

或者,无论Chrome存储了什么内容,您都可以编写自己的Tampermonkey脚本来填写这些字段.

Or you can write your own Tampermonkey script to fill in these fields, irregardless of what Chrome has stored.

如果您确实编写了Tampermonkey脚本,建议您使用

If you do write a Tampermonkey script, I recommend that you use a secure storage framework, don't hardcode login info into the script.