JavaScript无法修改的特殊输入框:实现原理、安全性及绕过方法问询
嘿,这个问题我之前研究过,刚好能给你讲清楚!这种前端输入框防篡改的实现、安全性以及绕开方法,我拆解成几个部分来说:
核心思路是把输入框的「显示值」和「真实值」分离,外部通过JS强制赋值只会修改显示值,而真实值只有用户手动输入才会更新,当输入框聚焦时,就用真实值覆盖显示值。常见的实现方式有两种:
监听
focus事件重置显示值
这是最常用的方案,开发者会把真实值存在隐藏字段、闭包变量或者元素的自定义属性里,当输入框聚焦时,立刻将显示值替换为真实值。比如Instagram的登录框大概率用了类似逻辑:const loginInput = document.querySelector('input[name="username"]'); // 存储真实值的变量,初始为空 let actualValue = ''; // 用户输入时同步真实值 loginInput.addEventListener('input', (e) => { actualValue = e.target.value; }); // 聚焦时用真实值覆盖显示值 loginInput.addEventListener('focus', () => { loginInput.value = actualValue; });当你用
document.getElementsByTagName("input")[0].value = "TestValue"赋值时,并不会触发input事件,所以actualValue还是空,聚焦后就会被重置为空。定时同步真实值
另一种方式是用setInterval定时检查输入框的显示值和真实值是否一致,不一致就强制覆盖。这种方式更“粗暴”,但能防止一些绕过focus事件的情况:const input = document.getElementsByTagName("input")[0]; let actualValue = ''; setInterval(() => { if (input.value !== actualValue) { input.value = actualValue; } }, 100); // 每隔100ms检查一次
说白了,这种纯前端的防护完全是“防君子不防小人”,没有真正的安全性可言:
- 它只能阻止不懂前端的用户或者简单的脚本篡改,对于稍微懂点开发者工具的人来说,绕开太容易了;
- 服务器端绝对不能依赖这种前端防护,因为攻击者完全可以跳过界面,直接构造HTTP请求发送数据,所以服务器必须做独立的校验;
- 甚至可能影响正常用户体验,比如某些自动填充工具的内容可能会被这个机制清空。
只要能让真实值和你设置的显示值同步,或者禁用重置逻辑,就能绕开:
手动触发
input事件同步真实值
给输入框赋值后,手动触发input事件,让真实值变量更新:const input = document.getElementsByTagName("input")[0]; input.value = "TestValue"; // 触发input事件,同步真实值 input.dispatchEvent(new Event('input'));这样聚焦后,真实值已经是你设置的内容,就不会消失了。
移除或禁用
focus事件监听
打开开发者工具,选中输入框(用$0快速获取),然后移除它的focus事件处理函数:// 先获取所有focus事件的处理函数,然后移除 const handlers = getEventListeners($0).focus; handlers.forEach(handler => $0.removeEventListener('focus', handler.listener));或者更简单,直接清空
onfocus属性:$0.onfocus = null;之后再赋值,聚焦就不会被重置了。
模拟真实用户输入
用JS模拟键盘输入,这种方式会自动触发input事件,同步真实值:const input = document.getElementsByTagName("input")[0]; input.focus(); // 模拟插入文本 document.execCommand('insertText', false, 'TestValue');修改DOM的真实属性并同步
在开发者工具的「Elements」面板里,直接修改输入框的value属性,然后保存。有些场景下这种修改会被识别为用户输入,自动同步真实值;如果不行,再手动触发input事件即可。
内容的提问来源于stack exchange,提问作者MMA

