不能用普通 做安全键盘,因其前端明文持有输入,易遭 xss 读取、事件监听或 devtools 抓取;需禁用原生输入,由自定义键盘触发加密提交,前端不留明文。

为什么不能用普通 <input type="password"> 做安全键盘
因为普通密码输入框在前端就明文持有用户输入,容易被 XSS 注入脚本直接读取 input.value、监听 keydown 事件、或通过 DevTools 实时抓取 DOM。金融/支付类场景要求「按键过程不暴露原始字符」,必须绕过原生输入框的文本流。
核心思路是:禁用真实 input 的键盘输入,所有按键由自定义键盘面板触发,只向后端提交加密后的结果(如 AES 加密串或动态 token + 密文),前端不留明文、不拼接字符串、不缓存 key。
- 禁用
input的onkeydown/oninput,设readonly或disabled(注意后者会丢失表单值) - 键盘按钮点击时,不更新
input.value,而是将按键映射为随机码(如'k1'、'k7')或立即加密 - 服务端需配套解密逻辑,且密钥绝不下发到前端
如何用纯 HTML + JS 实现防录屏/防截键的安全键盘
关键不是“画个键盘”,而是阻断一切可被自动化捕获的输入路径。以下是最小可行方案:
- 用
<div contenteditable="false"> 模拟输入框视觉效果,避免 <code>input元素被聚焦劫持 - 键盘按钮用
<button type="button"></button>,绑定onclick,每个按钮的data-key设为服务端预置的映射码(如data-key="a9f2"),而非真实字符 - 每次点击后,把
data-key推入数组,不拼接明文;提交前调用 Web Crypto API 的subtle.encrypt()加密整个序列(需提前协商好 IV 和公钥) - 禁用右键、选中、拖拽:
oncontextmenu="return false"、user-select: none、-webkit-user-drag: none
示例片段:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
<div id="safe-input" contenteditable="false" style="user-select:none;"></div> <div class="keyboard"> <button type="button" data-key="m3x8">1</button> <button type="button" data-key="p9z2">2</button> </div>
document.addEventListener('keydown') 为什么必须禁用
即使你隐藏了原生输入框,只要页面存在可聚焦元素,用户按物理键盘仍会触发全局 keydown,恶意脚本只需监听就能拿到 event.key 或 event.code。这不是“键盘组件没写好”,而是浏览器默认行为。
- 在安全键盘激活时,执行
document.addEventListener('keydown', e => e.preventDefault(), true)(注意 useCapture = true) - 但不要全局长期挂载——仅在键盘面板 visible 且输入域处于 active 状态时启用,关闭后立即
removeEventListener - 移动端需额外处理
touchstart和软键盘弹出逻辑,iOS Safari 对preventDefault更敏感,建议用inputmode="none"配合readonly
服务端验证时最容易忽略的三个点
前端再严,后端校验松动就全白搭。以下三点常被跳过:
- 加密密文必须带时间戳和随机 nonce,服务端拒绝 5 秒外或重复使用的请求,防重放
- 每个
data-key映射表应是一次性或短时效的,不能固定用同一套(比如永远'1' → 'm3x8'),否则攻击者截获几次密文就能反推映射关系 - 服务端解密后,**不记录原始密码明文**,也不做任何本地日志输出;若需审计,只记录操作类型、用户 ID、时间、是否成功,不存密文本身
真正难的不是画键盘,是让每一次按键都变成一次独立、有时效、不可逆的加密动作,并确保服务端不留下可关联的痕迹。










