
这次我们来看一个有点特别的项目作者在 Hacker News 的 Show HN 板块里公开了一次审计结果——把 8 个免费浏览器工具产生的 743 个 URL 全部拉出来逐个分析这些请求到底发往了哪里。这个项目没有复杂的模型不需要显卡也不涉及几千行代码它的核心是一个很多人会忽略的问题你用免费的在线截图、翻译、压缩、转换、OCR 工具时浏览器后台到底向哪些域名发送了数据这个问题的价值被严重低估了。免费在线工具通常靠广告或用户数据变现页面上一个隐藏的 iframe、一次看起来正常的图片加载、一个“导出报告”按钮都可能把页面内容、上传文件名、剪贴板信息、甚至 Cookie 转发到第三方域名。743 个 URL 里可能有一批是第一方功能接口也有一批是统计、遥测、广告归因甚至可能包含你不希望出现在日志里的内容数据。这个项目做的事情就是把“感觉有风险”变成“有清单、有分类、有依据”。本文我会顺着这个项目的思路拆解一套可以复用的浏览器工具审计流程先确定审计范围和用例再用 Playwright 自动完成工具操作并抓取所有请求 URL接着解析 HAR 文件做域名聚合分析和风险标记最后给出批量审计方案和常见问题排查。中间会附上可直接改用的 Node.js 和 Python 脚本。本文不涉及具体工具名和具体的 743 条 URL 细节也不会复现作者真实结果——重点是方法论你可以拿这套流程去审计自己团队正在用的任何在线工具。如果你正在做浏览器插件开发、要给团队选型在线工具或者关注数据合规这篇可以直接收藏。整个审计过程不需要 GPU普通开发机就能跑唯一需要花时间的是把你关心的“工具使用场景”拆成一条条可重复执行的用例。1. 核心能力速览先把这类“URL 审计项目”的规格说清楚。它不像大模型项目那样有显存、推理速度等指标核心规格是审计范围、抓取方式、分析维度和输出形态。能力项说明项目类型浏览器工具链 / 在线服务安全性审计审计范围8 个免费浏览器工具合计 743 个 URL核心方法网络请求抓取 URL 归类 域名风险画像自动化方案Playwright / Puppeteer 控制浏览器记录请求抓包备选方案mitmproxy、Charles、Fiddler、浏览器 HAR 导出输出形式URL 清单、域名分类表、风险标记、审计报告支持平台Windows / macOS / Linux 均可GPU 要求不需要CPU 浏览器即可批量任务支持按工具用例批量执行并合并结果适用人群前端开发、安全测试、隐私合规、技术选型负责人主要风险点HTTPS 证书、动态域名、工具端反爬、HAR 解析差异从材料来看这个项目的判断标准是比较清晰的一个免费浏览器工具如果在你完成一次操作后向超过预期范围的域名发送了包含页面内容、上传文件或身份标识的请求就值得被标记。审计的最终产物应该是两个清单一个是你主动访问的第一方功能 URL另一个是“你未必知道它存在”的第三方接收方 URL。2. 适用场景与使用边界这类审计不是安全研究人员的专利它对普通开发者其实更实用。第一类场景是团队在线工具选型。很多团队会统一采购或推荐在线工具比如 PDF 转换、图片压缩、短链生成、代码格式化。工具是否免费是一回事数据怎么流转是另一回事。审计结果可以直接进入选型评分表凡是把上传内容转发到未知域名的工具评分直接降一档。第二类场景是浏览器插件开发。插件开发者经常需要调用第三方服务但用户安装插件时并不清楚权限边界。用同样的抓取方法开发者可以模拟用户操作确认插件是否把自己页面里的 DOM 内容、表单值、图片地址发送到了不该发送的地方。第三类场景是隐私合规自查。国内外的个人信息保护法规都对“向第三方提供个人信息”有明确要求。如果企业内部的运营人员使用某个在线工具处理了客户数据企业有责任知道这个工具的数据流向。审计结果可以作为合规记录的佐证材料。使用边界同样重要。URL 审计只能在两种前提下做一是审计自己拥有的或自己使用的账号与设备二是获得了服务方明确授权的测试环境。不要用这套方法去抓取他人的会话、尝试绕过登录态也不要把抓到的 URL 清单用来批量爆破或者攻击工具服务商。抓包能看到的只是“请求发到了哪里”不代表对方一定在违规收集数据——很多第三方域名是 CDN、图片存储、字体库需要结合请求体内容、响应类型和域名注册信息综合判断不能看到陌生域名就直接下结论。3. 环境准备与前置条件这一节给出的是通用检查清单。因为每个在线工具的操作流程不同实际抓取的用例需要按目标工具调整。操作系统方面Windows、macOS、Linux 都可以跑重点是能安装 Chromium。个人建议用一台独立的开发机或虚拟机避免审计过程中把代理证书装进主力浏览器影响日常使用。基础依赖有三块Node.js 18 或更高版本用来跑 Playwright 脚本。Python 3.9 或更高版本用来做 HAR 解析和 mitmproxy 抓包。Chromium 浏览器由 Playwright 自动下载。磁盘方面需要预留 2GB 左右主要用于 Chromium 缓存和 HAR 文件。网络方面没有特殊要求但建议在可控网络环境下测试避免公司办公网络对代理抓包做拦截。安装依赖的命令如下# 初始化 Node.js 项目 npm init -y # 安装 Playwright npm install playwright # 下载 Chromium 内核 npx playwright install chromium# Python 侧安装 mitmproxy主要用于 HTTPS 解密抓包 pip install mitmproxy如果你不想引入额外的代理工具只用 Playwright 的 request 事件就够做大部分 URL 记录了。mitmproxy 适合需要拿到“请求体内容”和“响应体内容”的场景比如想知道工具是否真的把文件内容传出去了。两种方式可以组合用先跑 Playwright 拿到 URL 清单再用 mitmproxy 对重点域名做二次确认。4. 审计流程设计与请求抓取URL 审计第一步不是写代码而是设计用例。743 个 URL 看起来很唬人但它背后一定是多条用例的累积。每一条用例要尽量贴近真实用户的使用方式比如“打开工具页面 - 上传一张测试图片 - 执行压缩 - 下载结果”就是一个完整用例。用例设计有几个原则每个工具至少设计 3 条不同操作路径覆盖页面加载、文件上传、结果导出三个阶段。测试素材用固定的、不含真实用户数据的文件可以是一张带版本号的测试图、一个包含占位符的 PDF。每次审计前清空浏览器缓存和存储状态避免上一次操作的统计请求混入本次结果。设置固定的等待时间确保延迟加载的统计脚本、轮询请求能被记录到。对每个工具单独保存一份 HAR 或 URL 清单方便后续对比。抓取方式上Playwright 的page.on(request)是效率最高的入口。它能在请求发出时拿到 method、url、resourceType 和时间戳不需要额外配置代理。缺点是看不到请求体和响应体不过对第一轮“域名盘点”已经足够。启动服务后脚本会打印出该工具页面加载期间产生的所有请求。这一步能跑通说明抓取环境已经正确后面要做的是把“打开页面”替换成具体的上传、点击、转换操作。5. 自动化审计脚本Playwright 记录 URL下面给出一套可以直接改用的自动化审计脚本。这段脚本的核心逻辑是打开一个在线工具页面静置一段时间收集页面加载产生的全部请求然后把结果写入 JSON 文件。改造成具体工具时需要替换page.goto的地址并在跳转后加入对应的操作步骤比如page.setInputFiles上传文件、点击转换按钮、等待下载完成。const { chromium } require(playwright); const fs require(fs); (async () { const browser await chromium.launch({ // 建议先非无头模式观察确认用例操作能正常执行 headless: false }); const context await browser.newContext(); const page await context.newPage(); const urls []; page.on(request, (request) { urls.push({ url: request.url(), method: request.method(), resourceType: request.resourceType(), time: new Date().toISOString() }); }); // 替换成你要审计的在线工具地址 await page.goto(https://example-tool.com, { waitUntil: networkidle }); // 根据具体工具补充操作上传文件、点击按钮、等待结果 // await page.setInputFiles(input[typefile], ./test-fixture.png); // await page.click(#convert-btn); await page.waitForTimeout(15000); fs.writeFileSync(urls.json, JSON.stringify(urls, null, 2)); console.log(captured ${urls.length} urls); await browser.close(); })();运行这段脚本后urls.json里就是该工具一次会话的全部请求。注意这里的waitUntil: networkidle并不等于“所有请求都结束了”因为有些工具会定时上报埋点数据。所以我在页面操作完成后又加了一个 15 秒的等待窗口把那些加载完成 5 秒、10 秒后才发出的统计请求也纳入记录。如果要做 8 个工具的批量审计不建议把它们都塞进同一个浏览器上下文。不同工具之间的 Cookie、存储状态会互相污染而且某个工具的跳转可能会干扰另一个工具的用例执行。更好的做法是每个工具独立起一个 browser context跑完用例后关闭再把各个 JSON 文件合并成一个大清单进行解析。6. HAR 聚合分析与接口批量处理拿到了 JSON 里的 URL 清单下一步是聚合分析。要回答的核心问题是这 743 个 URL 到底属于哪些域名每个域名承担什么角色先给一个 Python 解析脚本它可以读取多个审计结果文件统计域名出现次数并把 URL 按资源类型分类。这样可以快速看出一个工具的请求是不是集中在第一方域名还是被大量第三方域名包围。import json import glob from urllib.parse import urlparse from collections import Counter, defaultdict all_urls [] for file_path in glob.glob(./audit_results/*.json): with open(file_path, r, encodingutf-8) as f: data json.load(f) all_urls.extend(data) domain_counter Counter() type_domain_counter defaultdict(Counter) for item in all_urls: url item[url] parsed urlparse(url) domain parsed.netloc resource_type item.get(resourceType, unknown) domain_counter[domain] 1 type_domain_counter[domain][resource_type] 1 print( domain frequency ) for domain, count in domain_counter.most_common(30): print(f{domain}\t{count}) print(\n domain by resource type ) for domain, type_counter in type_domain_counter.items(): print(f{domain}\t{type_counter})如果你选择用 HAR 文件而不是自记录的 JSON解析方式类似只是数据结构换成了log.entries[].request.url。HAR 文件通常比自记录文件大很多因为它还包含请求头、响应头、响应体等详细字段解析时要注意文件大小和时间开销。import json from urllib.parse import urlparse from collections import Counter with open(tool.har, r, encodingutf-8) as f: har json.load(f) domains [] for entry in har[log][entries]: url entry[request][url] domains.append(urlparse(url).netloc) for domain, count in Counter(domains).most_common(50): print(f{domain}\t{count})分析阶段可以把域名分成四类分类判断依据风险等级第一方功能域名与工具主域名同根提供页面、API、上传低第三方基础服务被大量网站使用的 CDN、字体、图片存储中统计与遥测域名含 analytics、metrics、tracking 等特征中高未知商业域名非基础服务、非统计且出现业务逻辑请求高判断一个未知域名是否有风险还可以补充三个维度看它是否接收了含有测试素材的请求体看它是否在短时间窗口内收到超过预期数量的请求看它的域名注册信息、备案信息或主站内容是否与工具业务相关。批量测试时建议把用例配置文件化。比如用 JSON 保存“工具名称 入口 URL 操作步骤 等待时间”然后由脚本统一读取执行。这样新增一个审计对象只需要加一条配置不用改主流程。{ tools: [ { name: image-compressor, url: https://example-tool.com, actions: [upload:./test-fixture.png, click:#compress-btn, wait:10000] }, { name: pdf-converter, url: https://example-pdf.com, actions: [upload:./test-file.pdf, click:#convert-btn, wait:15000] } ] }批量执行时还要考虑超时和重试。在线工具页面经常因为 CDN 节点问题加载缓慢脚本不能因为没有等到某个按钮就退出。常见做法是给每个操作步骤增加超时参数超过 20 秒则记录失败并继续下一个工具最后汇总一份失败清单单独处理。7. 资源占用与性能观察URL 审计的资源占用大头不在 CPU而在浏览器本身和日志文件体积。这里的观察粒度主要围绕三个指标抓取阶段的浏览器内存、HAR 文件膨胀速度、批量审计的总耗时。使用 Playwright 启动一个 Chromium 实例内存占用通常在数百 MB 级别。如果并行跑多个工具实例建议限制并发数。不要把 8 个工具一次性全开否则机器可能卡顿而且大量并发请求也会改变工具服务端的表现某些防爬策略可能因此触发。日志文件膨胀是很容易被忽略的问题。一个工具页面如果没有做过滤加载 5 分钟就可能产生几十 MB 的 HAR 文件。HAR 会完整记录请求头和响应头很多图片类请求的响应体数据也会被保存体积增长非常快。如果只做 URL 分析建议不要直接保存完整 HAR而是用脚本把 URL、method、resourceType、时间戳抽出来存成精简 JSON。这样 743 个 URL 最终可能只有几百 KB解析也更快。时间开销方面审计一个工具大概需要 1 到 3 分钟取决于页面操作步骤数和等待时间。8 个工具全部跑完大约 15 到 25 分钟这个环节可以完全自动化跑完再统一分析。如果用了 mitmproxy暂停抓包时要注意及时导出 HAR避免长期运行导致内存占用不断上涨。降低资源占用的具体手段设置browser.newContext({ ignoreHTTPSErrors: true })减少 HTTPS 证书错误导致的页面重试。使用page.route拦截图片、字体等非关键请求加快页面加载速度。定期清理 Playwright 的浏览器缓存目录和临时文件。批量任务中统一管理端口避免多个代理实例抢占同一个端口。这类审计无需 GPU也没有显存概念机器只要能流畅运行浏览器就足够。唯一的瓶颈通常是网速和工具服务端的响应速度。8. 常见问题与排查方法审计流程和很多自动化测试类似刚上手容易踩坑。下面是按实际常见情况整理的排查表。问题现象可能原因排查方式解决方案抓到的 URL 明显过少页面跳转到登录页或验证码页检查浏览器截图和页面标题在用例中增加登录步骤或使用测试账号看不到 HTTPS 请求体没有配置代理证书检查 mitmproxy 证书是否安装到系统信任区重新安装 mitmproxy CA 证书浏览器启动失败缺少系统依赖库查看 Playwright 错误日志运行npx playwright install-depsnpm 安装依赖失败registry 网络问题或权限问题更换 npm 镜像源后重试设置镜像源或使用npm install --registry...HAR 文件巨大未过滤图片和响应体检查文件体积改为只取 URL 字段不保存完整 HAR请求 URL 全部集中在第一方域名第三方请求被浏览器安全策略阻塞检查页面是否启用了严格 CORS / CSP改用 mitmproxy 在系统层抓包工具加载明显变慢Playwright 浏览器指纹被识别检查是否有反爬页面增加人工操作步骤减少无头模式特征批量任务卡在一个工具页面等待超时设置过短查看后台日志对每个步骤设置等待超时和失败跳过域名归属无法判断请求体加密或域名信息不明确使用 whois 或在线域名信息查询结合请求内容和注册信息综合标记风险其中“请求 URL 全在第一方域名”的现象最隐蔽。很多在线工具会通过服务端转发第三方请求浏览器端看到的只是同一个 API 域名但服务端可能已经把文件内容发送到了其他对象存储或数据分析平台。这种情况浏览器审计无法覆盖需要配合服务端日志或平台方的隐私政策来判断。还有一个常见问题是工具升级后 URL 变化。免费在线工具更换统计 SDK 是经常发生的事上个月还在的tracker.example.com这个月可能变成telemetry.another-sdk.com。所以审计结果要标注工具版本、审计时间和浏览器版本否则几个月后再看清单可能已经失真。9. 最佳实践与合规建议从项目标题看作者能数出 743 个 URL说明整个审计已经走过了“从零散请求到结构化数据”的过程。这套过程在工程化时可以提炼成几条最佳实践。第一隔离测试环境。为审计准备一个独立浏览器配置目录不要复用主力浏览器数据。这样可以避免自己的登录状态干扰测试结果也避免审计过程中意外读取到真实业务数据。const context await browser.newContext({ userAgent: Mozilla/5.0 ..., viewport: { width: 1280, height: 720 }, locale: zh-CN });第二测试素材要固定且无害。审计时应使用版本号明确的测试文件比如test-fixture-v20250601.png。这样即使文件内容被第三方服务器接收也不会造成真实数据泄露同时版本号还能帮你追踪哪个工具在哪个时间点上传了什么文件。第三风险标记要留证据。给某个域名打上高风险标签时应附上至少两个证据出现该域名的具体请求 URL、该请求携带的数据字段。不建议仅凭域名特征下结论因为很多“看起来可疑”的域名其实是工具在不同地区部署的 CDN 节点。第四定期重跑。在线工具的页面逻辑和 SDK 依赖变化很快一次干净的审计结果只代表审计时间点的状态。建议把审计脚本做成定时任务每周或每月对核心工具重跑一次输出差异报告。差异报告能帮你发现“新增的第三方域名”和“消失的旧域名”比重新看全部 URL 高效得多。第五合规意识要到位。涉及用户真实数据的工具审计应该在企业合规或法务确认后进行。抓包过程虽然只发生在测试环境但抓取到请求体内容时仍要注意不能把第三方服务的请求数据公开到不可控的渠道。输出的审计报告建议只保留域名、请求类型、数据字段名不展示完整的文件内容或 Cookie 值。第六结果要服务于决策。审计不应该是“证明某个工具是坏的”而是给团队一个明确的使用边界。一个工具如果有多个发送到未知域名的请求不一定马上弃用但至少应该限制它处理敏感文件或者改用私有部署替代方案。10. 总结这个 HN 项目的价值不在于 743 这个数字而在于把“免费浏览器工具背后到底连接了多少域名”这件事做成了可复现的审计过程。作者没有停留在抱怨工具乱发请求而是用实际数据告诉我们一次简单的在线操作后台产生的网络请求数量远超直觉。如果你想复现这套流程建议从最简单的场景开始选一个你经常用的图片压缩或 PDF 转换工具设计一条“上传文件 - 等待转换 - 下载结果”的用例用 Playwright 记录 URL再用 Python 做域名分布统计。第一次跑通后你会立刻看到以前看不见的那部分网络流量。最容易踩的坑集中在两个环节一个是 HTTPS 抓包证书没配好导致数据缺失另一个是工具升级导致旧脚本选择器失效。前者通过 mitmproxy 证书设置能解决后者需要给用例增加稳定等待和超时跳过机制。后续可以扩展的方向包括把审计脚本接入 CI每天自动对团队常用在线工具做请求差异检测把域名分类结果导入数据库形成企业内部的可疑域名库结合请求体大小和时间窗口识别可能的批量数据传输行为。做完这些一个简单的 URL 审计项目就可以升级成团队内部的数据流监控小工具。