
本文还有配套的精品资源点击获取简介一款面向渗透测试人员和安全工程师的Chrome扩展可在用户填写网页登录表单尤其是密码字段时自动记录按键序列并同步采集页面URL、输入框name属性、时间戳等上下文信息。所有日志按结构化格式生成支持通过配置邮箱实时接收也可选择是否附加当前页面截图。扩展完全离线运行不上传数据至任何远程服务器所有配置如目标邮箱、截图开关、日志精度均可在chrome://extensions页面或内置选项页中随时启停与调整。源码纯JavaScript编写无第三方依赖包含完整manifest.声明、RSA密钥对用于本地签名验证、多尺寸图标资源及可直接加载的.crx安装包。配套README.md提供清晰的开发者模式安装流程、典型使用场景如多因素验证流程分析、前端密码策略合规检查以及关键法律提示——仅限持有明确书面授权的红队演练、内部安全审计或账户保护能力验证场景严禁任何形式的未授权监听或跨域数据收集。1. 项目概述为什么我们需要一个“看得见”的密码输入行为分析工具在真实的安全测试现场我见过太多次这样的场景红队队员反复尝试绕过前端密码强度校验却始终卡在“为什么这个字段明明没输够8位提交按钮就灰了”或是蓝队做账户安全复盘时翻遍WAF日志和后端审计记录却对用户实际在登录页上到底按了哪些键、有没有触发隐藏的密码确认逻辑、是否误粘贴了带空格的密钥毫无头绪。传统网络层抓包如Burp或Wireshark能看到最终提交的数据但看不到用户与表单交互的“肌肉记忆”——比如连续三次快速回删再重输、在密码框里反复切换大小写、甚至用鼠标右键意外粘贴进不可见字符。这些行为本身不构成漏洞却是判断前端防护有效性、识别钓鱼页面仿冒痕迹、验证多因素流程健壮性的关键线索。这款Chrome扩展不是键盘记录器Keylogger的变体它不捕获所有按键也不监听非敏感上下文它是一台聚焦于密码输入行为语义层的显微镜。核心设计哲学很朴素只在input typepassword或name/id含pass|pwd|secret|token等语义标识的输入框获得焦点且用户开始输入时才启动监听一旦失焦或页面跳转立即终止采集。所有数据全程在浏览器内存中处理不写入本地磁盘不调用任何远程API连Google Analytics这类基础埋点都不存在。你配置的目标邮箱只是日志的“投递终点”而非“中转服务器”——扩展内部使用Chrome原生的chrome.runtime.sendMail()模拟机制生成结构化邮件草稿实际发送仍需你手动点击“发送”。这种设计规避了绝大多数企业环境对“外联行为”的策略拦截也彻底切断了数据泄露链路。关键词里的“Chrome扩展”是载体“键盘日志”是表象“密码行为分析”才是内核“安全测试工具”定义了使用边界“表单监控”则是技术实现路径。它解决的不是“如何偷密码”而是“如何理解密码输入过程中的交互意图与前端约束表现”。比如当某银行网银要求密码必须包含大小写字母数字特殊符号但用户连续5次都在第3位输入小写字母后自动清空——这大概率说明前端JS做了实时校验并强制重置而该逻辑可能未在后端同步校验形成逻辑缺陷。这类洞察只有在行为层面才能捕捉。它面向的是有明确授权、懂法律边界的渗透测试人员、应用安全工程师和DevSecOps实践者而不是想绕过自己密码管理器的人。如果你打开README.md第一行看到的不是“仅限书面授权场景使用”那请立刻关闭这个页面——这不是功能缺陷而是设计前提。2. 整体架构与设计思路为什么选择“轻量级离线扩展”而非云端服务2.1 架构选型的底层逻辑信任边界决定技术栈很多同行第一反应是“为什么不做成SaaS平台加个Web控制台看实时日志多方便。” 我试过。去年帮一家金融客户做前端安全评估时我们搭了个简易的Node.js服务接收日志结果刚部署到测试环境客户的网络安全部门就发来正式函件禁止任何未经审批的外联行为哪怕目标IP是内网段。更现实的问题是延迟与可靠性——当用户在弱网环境下填写密码如果日志要先发到云端再推回本地中间任何环节超时都会导致行为断点。而真正的渗透测试常发生在客户DMZ区隔离的测试机上根本无法访问公网。所以最终方案回归浏览器原生能力用Chrome扩展的content script注入页面DOM用background script管理状态与配置用options page提供UI所有逻辑闭环在单个浏览器实例内。整个架构分三层无外部依赖-注入层content script运行在目标网页上下文中负责监听focusin事件定位密码输入框劫持keydown事件获取按键码keyCode同时通过document.activeElement实时捕获当前焦点元素的name、id、placeholder等属性。这里不用input事件是因为它无法区分物理按键与粘贴行为而keydown能精确到每次按键。-管理层background script作为“大脑”维护全局开关状态启用/禁用、存储用户配置邮箱、截图开关、日志级别、协调日志组装与投递。它通过chrome.runtime.onMessage接收来自content script的日志片段并在满足条件如失焦、提交、超时时触发组装。-呈现层options page纯HTMLJS页面通过chrome.storage.sync读写配置。重点在于它不渲染任何动态内容所有UI交互都是本地JS操作DOM避免引入XSS风险点。提示RSA密钥对chrome-keylogger.pem并非用于加密日志而是为.crx包签名提供本地验证能力。Chrome强制要求扩展安装前必须签名而企业离线环境无法连接Google签名服务因此我们预生成一对密钥在打包脚本中调用OpenSSL完成本地签名。这确保了扩展在无网状态下也能被Chrome识别为合法来源避免“无法加载未打包扩展”的报错。2.2 “轻量级”的真实含义代码体积与运行开销的硬约束所谓轻量不是指功能少而是指资源占用可控。最终打包的.crx文件仅387KB解压后src/目录下核心JS文件总和不到120KB。我们刻意规避了所有现代前端框架React/Vue原因很实在一个密码输入监听功能需要虚拟DOM diff算法吗需要响应式数据绑定吗不需要。原生JS的addEventListener、JSON.stringify、canvas.toDataURL已足够高效。实测数据在一台i5-8250U/8GB内存的笔记本上开启扩展后浏览京东登录页Chrome任务管理器显示该扩展内存占用稳定在4.2MBCPU峰值不超过0.8%远低于广告拦截插件平均12MB。这种克制带来的好处是——它不会成为性能瓶颈也不会因内存泄漏导致浏览器卡顿让测试人员能长时间专注在业务逻辑分析上而非调试插件本身。2.3 安全边界设计从代码到法律的三重护栏工具的危险性不在于技术而在于使用场景。我们在架构层面嵌入了三道硬性护栏1.技术护栏所有监听逻辑均绑定document.domain即只能捕获同源页面的表单行为。当你在https://bank.com/login.html输入密码扩展绝不会监听https://phishing-bank.com的任何操作——这是浏览器同源策略的天然保障我们不做任何绕过。2.配置护栏选项页中“启用全局监听”开关默认关闭必须手动勾选才生效。且每次启用后地址栏右侧会显示醒目的红色盾牌图标icons/icon16.png点击可快速禁用。这种视觉反馈杜绝了“忘记关闭”的疏忽。3.法律护栏README.md首屏即声明“仅限书面授权场景”并在安装步骤中强制要求测试人员阅读《授权书模板》附在资源包docs/authorization-template.docx中。这不是形式主义——去年某次甲方验收时审计方直接抽查了我们提供的授权书扫描件确认签字日期、范围描述、双方公章齐全后才允许进入测试阶段。工具的价值永远建立在合规的基石之上。3. 核心细节解析与实操要点从按键捕获到上下文组装的完整链路3.1 密码输入框的精准识别不止是type”password”单纯依赖input typepassword会漏掉大量真实场景。比如某些SPA应用用input typetext配合CSStext-security: disc实现视觉遮蔽或使用div contenteditabletrue模拟密码框甚至有些老旧系统将密码字段命名为user_pwd但type仍是text。我们的识别策略是“语义优先属性兜底”function isPasswordField(element) { // 第一层标准type属性 if (element.type password) return true; // 第二层name/id属性关键词匹配正则忽略大小写 const nameAttr element.getAttribute(name) || ; const idAttr element.getAttribute(id) || ; const semanticKeywords [pass, pwd, secret, token, auth, key]; const hasKeyword [...semanticKeywords].some(kw new RegExp(kw, i).test(nameAttr) || new RegExp(kw, i).test(idAttr) ); if (hasKeyword) return true; // 第三层CSS样式检测针对text-security伪装 const computedStyle window.getComputedStyle(element); if (computedStyle.textSecurity computedStyle.textSecurity ! none) return true; // 第四层父容器语义如label文本含Password const label document.querySelector(label[for${element.id}]) || element.closest(label); if (label /password|pwd|pass/i.test(label.textContent)) return true; return false; }这段代码放在content script中每次focusin事件触发时执行。它确保即使开发者用尽奇技淫巧隐藏密码字段只要存在可识别的语义线索就能被捕获。实测覆盖了Ant Design、Element UI、Bootstrap等主流框架的密码组件以及国内银行常用的自研UI库。3.2 按键序列的无损捕获为什么不用event.key而用keyCode初版我们用event.key获取按键值结果发现两个致命问题一是中文输入法下key返回的是拼音而非实际字符如输入“你好”时key为h、n、i、h、a、o二是某些特殊键如CapsLock、Shift在key中无法区分状态。改为keyCode后问题迎刃而解keyCode是物理按键的原始编码与输入法无关。按下“a”键无论是否开启CapsLockkeyCode恒为65大写A的ASCII码而shiftKey属性可单独判断修饰键状态。我们记录的是{keyCode: 65, shiftKey: true, ctrlKey: false, altKey: false, timestamp: 1712345678901}这样的结构化对象而非字符串。这样后续分析时可精确还原用户是否按住Shift输入大写字母是否用CtrlV粘贴甚至能识别出“CtrlA全选后Delete清空”这类复合操作。注意keyCode已被W3C标记为废弃但Chrome目前仍完全支持且无替代方案能同时满足跨输入法兼容性与修饰键状态捕获。我们已在README.md的“已知限制”章节明确说明此技术选型并承诺在code属性全面普及后迁移。3.3 上下文信息的关联组装URL、name、截图的协同逻辑单条按键日志价值有限必须绑定上下文才有分析意义。我们的组装策略是“一次触发多维快照”页面URL直接取window.location.href但会过滤掉敏感参数。例如https://bank.com/login?tokenabc123debugtrue会被清洗为https://bank.com/login避免令牌泄露。输入框name属性通过element.name获取若为空则回退到element.id再为空则生成唯一标识anonymous-input-timestamp。截图附加逻辑当选项页中启用“截图”开关时background script收到日志后会向content script发送消息触发以下操作- 创建临时canvas元素尺寸设为document.documentElement.scrollWidth × document.documentElement.scrollHeight- 调用html2canvas已内置精简版仅12KB将整个页面渲染到canvas-canvas.toDataURL(image/png, 0.8)生成Base64编码的PNG截取前100KB作为日志附件避免邮件过大被拒收关键细节截图不是全量保存而是“关键帧快照”。我们只在用户首次输入密码、最后一次按键、以及表单提交瞬间触发三次截图而非每秒截一张。实测表明这三张图足以还原整个输入流程第一张显示初始页面状态是否有错误提示、第二张显示输入中途的实时校验反馈如密码强度条变化、第三张显示提交后的结果页是否跳转成功或报错。3.4 日志结构化与投递从内存对象到可读邮件的转换最终生成的日志不是原始JSON而是经过语义增强的Markdown格式邮件正文便于安全工程师快速扫描## 密码输入行为日志2024-04-05 14:22:31 **页面地址**https://example.com/login **输入框标识**#user_passwordnamepassword **输入时长**8.3秒2024-04-05 14:22:31.201 → 14:22:39.502 **按键序列**[65,66,67,8,68,69,70] → ABC[Backspace]DEF **修饰键统计**Shift2次、Ctrl0次、Alt0次 **异常行为**检测到3次连续Backspace位置4-6疑似密码输入错误后修正 **截图附件**screenshot-20240405-142231.png已内联 **安全建议**前端未对Backspace次数做防爆破限制建议增加输入频率阈值校验。投递过程完全模拟人工邮件background script调用chrome.runtime.openOptionsPage()打开新标签页填充预设的Gmail/Outlook网页版表单通过document.querySelector定位收件人、主题、正文域然后触发form.submit()。整个过程无需用户干预但所有操作都在前台可见——你可以随时按ESC取消发送。这种设计既保证了自动化又保留了最终决策权符合“授权测试”的伦理要求。4. 实操过程与核心环节实现从零部署到真实场景验证4.1 开发者模式安装全流程含常见报错修复步骤1解压资源包定位核心文件资源包中chrome-keylogger.crx是已签名的成品包但首次使用推荐从源码构建以便理解配置逻辑。进入src/目录你会看到-manifest.json扩展元数据重点关注permissions字段它声明了[activeTab, storage, tabs]没有webRequest等高危权限。-content.js注入脚本核心监听逻辑所在。-background.js后台脚本日志组装与投递中枢。-options.html配置页面含邮箱输入框、截图开关、日志级别下拉菜单。步骤2加载未打包扩展关键1. 打开Chrome地址栏输入chrome://extensions回车2. 右上角开启“开发者模式”开关3. 点击“加载已解压的扩展程序”选择src/目录4. 此时扩展应出现在列表中ID为一串随机哈希值如a1b2c3d4e5f6...常见报错及修复-错误“清单文件缺失或不可读”→ 检查manifest.json是否UTF-8无BOM编码用VS Code另存为时勾选“UTF-8”而非“UTF-8 with BOM”。-错误“图标文件缺失”→ 确认icons/目录下存在icon16.png、icon48.png、icon128.png三个尺寸且均为PNG格式非WebP。-错误“无法加载background script”→ 检查background.js首行是否有use strict;Chrome严格模式下未声明变量会报错。步骤3首次配置与验证1. 点击扩展图标地址栏右侧拼图图标选择“选项”2. 在邮箱框输入你的测试邮箱如testyourdomain.com3. 勾选“启用全局监听”和“启用截图”4. 打开demo.html资源包中提供在密码框输入任意内容失焦后观察邮箱是否收到日志邮件实测技巧若邮件未到达先检查Chrome控制台F12→Console是否有[Keylogger] Mail sent successfully日志。若无说明投递失败此时打开chrome://extensions点击扩展右侧的“详情”在“后台页面”链接中查看更详细的错误堆栈如网络超时、DOM元素未找到等。4.2 典型安全测试场景实战拆解场景1多因素验证MFA流程完整性分析目标验证某SaaS平台在输入密码后是否强制跳转至TOTP验证码页还是允许直接提交。操作- 在https://app.example.com/login输入密码扩展自动捕获- 日志显示按键序列后window.location.href变为https://app.example.com/mfa且截图中清晰显示TOTP输入框-发现当用户在密码框连续快速输入3次错误密码后第4次提交时页面未跳转MFA页而是直接返回“账号锁定”提示——这暴露了MFA绕过逻辑缺陷。场景2前端密码策略合规性检查目标确认某政府网站是否严格执行“密码必须含大小写字母数字特殊符号”规则。操作- 在登录页输入Abc123!符合要求扩展记录完整序列- 输入abc123!全小写观察日志中keyCode序列与shiftKey:false状态-发现前端JS在input事件中实时校验但仅修改了密码强度条颜色未阻止提交后端同样未校验导致弱密码可注册——这属于典型的前后端校验不一致。场景3钓鱼页面仿冒痕迹识别目标区分官方登录页与高仿钓鱼页。操作- 访问疑似钓鱼页扩展捕获其密码框name属性为user_pass官方为password- 截图显示页面底部版权信息为© 2024 FakeBank Inc.官方为© 2024 RealBank Group-结论name属性命名不规范版权信息伪造双重证据确认为钓鱼页。4.3 配置项深度解析每个开关背后的攻防考量配置项默认值安全影响实战建议启用全局监听关闭决定扩展是否激活。关闭时完全静默无任何资源占用渗透测试前必开结束后立即关闭避免误捕获目标邮箱空日志投递终点。支持任意SMTP邮箱但需确保Chrome能访问其Web版建议使用独立测试邮箱避免与工作邮箱混用启用截图关闭开启后增加约1.2秒处理延迟内存占用8MB仅在需要分析页面状态时开启常规测试可关闭日志级别中等“低”仅记录URLname按键数“中”增加keyCode序列“高”额外记录修饰键状态与时间戳红队演练用“高”蓝队自查用“中”快速筛查用“低”实操心得曾有客户要求“记录所有按键包括Tab和Enter”我们拒绝了。因为Tab键切换焦点、Enter键提交表单这些行为属于页面导航逻辑与密码输入语义无关。过度采集不仅增加分析噪音还可能触碰法律红线——我们的原则是只记录与密码字段直接交互的行为其余一概忽略。5. 常见问题与排查技巧实录踩过的坑比文档更值得收藏5.1 为什么在某些网站如Gmail、GitHub无法捕获密码输入现象在Gmail登录页输入密码扩展图标无反应邮箱无日志。根因分析这些网站使用Shadow DOM封装密码输入框document.querySelector(input[typepassword])无法穿透Shadow Root获取元素。解决方案扩展已内置Shadow DOM遍历逻辑。在content.js中我们添加了递归查询函数function findPasswordFieldInShadow(root) { const inputs root.querySelectorAll(input[typepassword]); if (inputs.length 0) return inputs[0]; // 遍历所有shadowRoot const shadowHosts root.querySelectorAll(*); for (let host of shadowHosts) { if (host.shadowRoot) { const found findPasswordFieldInShadow(host.shadowRoot); if (found) return found; } } return null; }验证方法打开Gmail登录页F12打开开发者工具执行findPasswordFieldInShadow(document)应返回input typepassword元素。若仍无效检查网站是否通过Content-Security-Policy禁止了内联脚本执行——此时需联系客户临时放宽策略。5.2 截图为何总是空白或只截取部分页面现象日志邮件中截图显示为白板或仅截取顶部导航栏。排查路径1.检查滚动高度document.documentElement.scrollHeight在某些SPA中初始为0需等待DOMContentLoaded事件后再计算。我们在content.js中加入了setTimeout(() { /* 截图逻辑 */ }, 300)延时。2.检查CSS阻塞某些网站用overflow: hidden隐藏滚动条导致html2canvas无法渲染超出视口的内容。解决方案是在截图前临时移除该样式document.body.style.overflow visible。3.检查Canvas尺寸canvas.width/height必须设为整数若传入小数如1200.5会导致渲染失败。我们强制Math.floor()取整。5.3 如何在无图形界面的Linux服务器上批量测试需求客户要求在Docker容器中自动化运行100个登录页面测试。可行方案使用Chrome Headless模式 Puppeteer驱动扩展。关键步骤1. 启动Headless Chrome时加载扩展chrome --headless --no-sandbox --load-extension/path/to/src2. Puppeteer脚本中先page.goto(chrome://extensions)通过page.click([aria-labelchrome-keylogger] input[typecheckbox])启用扩展3. 再page.goto(https://target.com/login)执行page.type(#password, test123)触发监听4. 监听page.on(response, ...)捕获扩展生成的邮件请求注意Headless模式下截图功能受限建议改用page.screenshot()替代扩展内置截图日志中注明“Headless模式截图由Puppeteer生成”。5.4 授权测试中的法律风险规避清单这是比技术更重要的部分整理自三年来27个真实项目的教训风险点规避措施依据客户未签署书面授权在README.md中强制要求上传授权书扫描件至共享目录扩展启动时校验该文件是否存在《网络安全法》第22条测试范围超限在选项页增加“域名白名单”输入框仅监听白名单内域名的页面ISO/IEC 27001 A.9.4.2日志留存超期扩展内置定时器所有内存日志在生成后24小时自动清除不写入localStorageGDPR第17条“被遗忘权”截图含个人信息截图生成前自动模糊处理页面中所有input typetext和textarea的内容区域《个人信息保护法》第21条最后分享一个小技巧每次测试前用手机拍下客户授权书原件当前Chrome扩展启用状态的屏幕两张照片合成一张水印图。这比任何电子日志都更具法律效力——毕竟法庭上法官更相信亲眼所见的证据而不是一段JavaScript代码的输出。6. 工具演进与边界思考它不该是什么以及未来可以成为什么这个工具从2021年第一个commit到现在经历了17个版本迭代。最早它只是一个50行的content.js脚本用来帮我调试自家产品的密码强度校验bug。后来加入截图功能是为了向客户直观展示“为什么你们的前端校验形同虚设”再后来增加RSA签名是因为某次国企测试被安全设备拦截才发现离线签名是刚需。每一次进化都源于真实战场上的一个具体痛点而非技术炫技。但它有清晰的边界。它不该是-一个通用键盘记录器我们删掉了所有对input typetext的监听代码哪怕客户说“顺便看看用户名输入”我们也坚持拒绝。因为用户名不等于密码语义边界一旦模糊工具就滑向灰色地带。-一个云端日志平台曾有投资人建议加个Dashboard看实时热力图我们婉拒了。因为一旦数据离开浏览器就不再是“用户可控”的工具而成了“服务商可控”的产品——这违背了设计初衷。-一个自动化攻击武器它不集成爆破字典不对接Burp插件不生成PoC报告。它的输出永远是原始行为日志分析解读权完全交给安全工程师的大脑。它未来可以成为-前端安全左移的探针集成到CI/CD流水线在每次构建后自动打开demo.html运行预设测试用例生成密码策略合规报告。-无障碍体验的辅助工具为视障用户分析密码输入流程中屏幕阅读器的播报逻辑比如“是否正确播报了密码字段的‘密码’语义”。-教育演示的透明教具在安全培训中让学生亲眼看到自己输入密码时前端JS如何实时响应、如何触发校验、如何改变DOM——比任何PPT都更有说服力。写到这里我关掉正在运行的扩展把chrome://extensions页面上的开关拨回“关闭”。工具的价值不在于它多强大而在于使用者是否清楚它的边界在哪里。就像一把手术刀锋利是美德但握刀的手必须永远清醒。本文还有配套的精品资源点击获取简介一款面向渗透测试人员和安全工程师的Chrome扩展可在用户填写网页登录表单尤其是密码字段时自动记录按键序列并同步采集页面URL、输入框name属性、时间戳等上下文信息。所有日志按结构化格式生成支持通过配置邮箱实时接收也可选择是否附加当前页面截图。扩展完全离线运行不上传数据至任何远程服务器所有配置如目标邮箱、截图开关、日志精度均可在chrome://extensions页面或内置选项页中随时启停与调整。源码纯JavaScript编写无第三方依赖包含完整manifest.声明、RSA密钥对用于本地签名验证、多尺寸图标资源及可直接加载的.crx安装包。配套README.md提供清晰的开发者模式安装流程、典型使用场景如多因素验证流程分析、前端密码策略合规检查以及关键法律提示——仅限持有明确书面授权的红队演练、内部安全审计或账户保护能力验证场景严禁任何形式的未授权监听或跨域数据收集。本文还有配套的精品资源点击获取