Kirill89/webcensus

GitHub: Kirill89/webcensus

一个漏斗式多阶段流水线,用于在单机上快速从数百万域名中精确搜索并验证特定 URL 路径文件的存在。

Stars: 0 | Forks: 0

# WebCensus 一个快速 pipeline,用于在单台机器上以合理的时间,在**数百万个域名**中搜寻特定的文件路径(例如 `/.well-known/security.txt`、 `/robots.txt`、`/ads.txt`、`/humans.txt`、`/sitemap.xml`)。 整个流程运行在一个可复现的 Docker 沙箱中。每个阶段都是一个 狭窄的漏斗,尽可能以极低的成本剔除非候选目标,因此 开销昂贵的阶段只会处理通过前一层过滤存活下来的主机。 ``` domain list ─► DNS (A records) ─► HTTPS probe ─► bulk fetch ─► verify massdns skim (Rust) curl --parallel bun UDP-fast status + cert bounded retries shape gate ``` ## 使用方法 ``` make shell # build & enter the sandbox ./scripts/step1_download_domain_list.sh # or bring your own data/domains.txt ./scripts/step2_massdns.sh ./scripts/step3_probe_status.sh ./scripts/step4_curl_config.mjs ./scripts/step5_curl.sh ./scripts/step6_filter.mjs ``` 所有产物都将落在宿主机的 `./data/` 目录中(该目录会挂载到容器内)。 ## 流水线 (pipeline) ### 1. 域名列表 — `step1_download_domain_list.sh` 下载 [Chrome UX Report 排名前列的站点](https://github.com/zakird/crux-top-lists) (公开的 Top-N 列表中最“真实”的一个,基于实际 Chrome 用户 访问量进行排名),剥离排名列和 `https://` 协议,并写入 `data/domains.txt` —— 每行一个顶级域名。 只要输出格式是每行一个域名,你可以替换为任何其他来源(参见[域名列表来源](#domain-list-sources))。 ### 2. DNS 解析 — `step2_massdns.sh` 使用 [massdns](https://github.com/blechschmidt/massdns) 针对 `resolvers.txt`(一组精选的公共递归解析器 —— Cloudflare、 Quad9、Google、AdGuard、OpenDNS 等)运行,为每个域名获取 A 记录。 - 输出:`data/dns.ndjson`(massdns 的 JSON 格式) - 为什么它很快:massdns 通过解析器池并行发送 UDP 查询;在单台机器上可达到每秒数万次查询。其 JSON 输出是 `skim` 直接消费的格式 —— 无需中间转换。 ### 3. HTTPS 状态探测 — `step3_probe_status.sh` 针对每个已解析的主机运行 `skim`,这是一个专为异步探测构建的 Rust 工具(参见 `skim/`)。对于每台主机,它会: 1. 打开一个到 `:443` 的 TCP 连接(可配置)。 2. 使用**记录验证器**执行 TLS 握手 —— 证书链验证会运行完毕并记录结果,但无效证书不会中止握手。这使得单次扫描既能捕获 HTTP 状态,*又*能判断证书是否可信。 3. 发送一个原始的 HTTP/1.1 `GET ` 请求。 4. **仅读取状态行**并关闭 socket。 输出行(`data/status.ndjson`)如下所示: ``` {"url":"https://example.com/.well-known/security.txt","status":"success","code":200,"cert_ok":true} ``` 为什么它很快: - 仅读取状态行 —— 不读取 body,不消耗 body 的带宽。 - 通过 `tokio` 信号量限制并发上限(默认为 100,可通过 `--concurrency` 调整)。 - 严格的逐阶段超时设置(连接 / 握手 / 读取),因此无响应的主机会在几秒内判定失败。 - 可恢复:传递 `--start-line N` 可在崩溃后继续执行。 - 预扫描会扫描一次输入以计算可探测的行数,从而提供真实的预计剩余时间 (ETA); `--skip-precount` 可在恢复执行时跳过此步骤。 ### 4. 构建 curl 配置 — `step4_curl_config.mjs` 流式读取 `data/status.ndjson` 并写入 `data/urls.curl`,这是一个 curl `-K` 配置 文件,其中为每个满足 `cert_ok && status == "success" && code == 200` 条件的 URL 添加一条记录: ``` url = "https://example.com/.well-known/security.txt" output = "example.com_.well-known_security.txt" url = "https://github.com/.well-known/security.txt" output = "github.com_.well-known_security.txt" ``` 每个 `output =` 是将其 URL 中的非字母数字字符替换为 `_` 后的结果,因此文件 落地时具有稳定且抗冲突的名称。该脚本还会输出一份快速的 合理性检查:有多少行的 `code == 200`,以及总共有多少行是可探测的。 为什么作为单独的阶段:将配置生成保留在 JS 中,意味着 URL 形状的 过滤器和文件名规则与 pipeline 的其余逻辑放在一起, 而 curl 调用本身仍然只需一行命令。 ### 5. 批量抓取 — `step5_curl.sh` 运行 `curl --parallel -K data/urls.curl` 将每个 URL 下载到 `data/unfiltered/`。这些参数专为“从许多不同的 主机下载许多小文件”进行了调优: - `--parallel-max 50` —— 并发传输中的最大连接数。 - `--max-filesize 5M` —— 预检拒绝 `Content-Length > 5MB` 的响应。 - `--max-time 10` —— 每次尝试的总挂钟时间上限(防止服务器 在没有 `Content-Length` 的情况下永远滴答传输数据)。 - `--connect-timeout 3` —— TCP 连接超时预算。 - `--retry 2 --retry-delay 5 --retry-max-time 30` —— 有限的重试预算,使得不稳定 的主机无法长时间占用其处理槽。 为什么使用 curl `--parallel` 而不是 aria2c / wget2:curl 是唯一能够硬性限制响应**大小**(`--max-filesize`)的主流工具 —— 当服务器 针对你想要的文件返回 200 状态码及数兆字节的 HTML 时,这一点很重要。它还运行 在单个进程中,因此 100 万个 URL 不需要执行 100 万次 `fork()` 调用。 ### 6. 内容形状验证 — `step6_filter.mjs` 离线遍历 `data/unfiltered/` 并将存活文件复制到 `data/filtered/`。 默认的 `text-file` 验证器会拒绝: - 短于 16 个字符的 body(空内容 / “Not Found” / “OK”), - 包含控制字符或无效 UTF-8 的 body(二进制噪声), - 看起来像 HTML、PHP 源码或 JSON 的 body(某些服务器对每个路径 都会以 SPA 外壳或通用 JSON 错误返回 200-OK)。 对于应该是 JSON 的路径,还提供了 `json` 验证器;将其作为 第一个参数传入: ``` ./scripts/step6_filter.mjs json ``` 为什么作为单独的阶段:验证器是**纯离线的** —— 无网络请求,无 顺序约束,幂等,并且可以使用不同的规则重新运行而无需 重新抓取。在 `step6_filter.mjs` 中添加新的验证器并重新运行; 带宽已经消耗过了。 ## 为什么端到端如此快速 该 pipeline 呈漏斗状。每个步骤的*单主机*处理开销大约比 下一步低一个数量级,因此开销昂贵的阶段永远只会处理 输入的一小部分: | 阶段 | 单主机开销 | 剔除内容 | |-------------------|----------------------------|------------------------------------------| | massdns | 一次 UDP 往返 | 已停放 / 死亡 / NXDOMAIN 的域名 | | skim | 一次 TLS + 状态行 | 无 443 端口、无效证书、非 200 状态码的主机 | | curl --parallel | 一次完整的 HTTPS GET (有上限)| 过大 / 挂起 / 不可达的主机 | | filter (离线) | 每个文件一次正则表达式匹配 | 200-OK 但实际并非目标文件的噪声数据 | 此外:massdns 的输出 → skim 的输入使用的是相同的 NDJSON;skim 的输出 → curl 配置只需一次流式处理。各阶段之间没有高开销的格式转换, 并且验证器阶段完全不碰网络。 ## 域名列表来源 ### 排名前约 100 万列表 (免费) - **Tranco** — 研究级综合排名。稳定,每月更新。https://tranco-list.eu - **Cisco Umbrella Top 1M** — 来自 Umbrella 解析器的 DNS 查询量。每日更新;变动较大。http://s3-us-west-1.amazonaws.com/umbrella-static/index.html - **Majestic Million** — 按引用子网排序(链接图谱)。每日更新。https://majestic.com/reports/majestic-million - **Cloudflare Radar Top 1M** — 来自 1.1.1.1 的查询量。https://radar.cloudflare.com/domains - **Chrome UX Report (CrUX)** — 按真实 Chrome 用户访问量排名的顶级站点。所有这些列表中最“真实”的一个。每月通过 BigQuery 发布。https://github.com/zakird/crux-top-lists *(`step1` 中的默认选项)* ### 更大的列表 (1000 万+) - **Open PageRank Top 10M** — 基于 Common Crawl 链接图谱。https://www.domcop.com/openpagerank/what-is-openpagerank - **DomCop Top 10M** — 聚合 Open PageRank;完整版需付费,提供免费样本。 ### 超大规模 (1 亿+) - **DNS zone files** — 每个 TLD 的已注册域名完整列表。 - Verisign 提供的 `.com`/`.net`(仅 `.com` 就约有 1.6 亿个)。 - ICANN CZDS 提供数百个 TLD:https://czds.icann.org - 免费但需要签署访问协议。 - **Common Crawl URL index** — 从数十亿抓取的 URL 中提取唯一域名。https://commoncrawl.org ### 实时 / 持续更新 - **Certificate Transparency logs** (crt.sh, certstream) — 签发的每个 TLS 证书的实时信息流。有用视角:新建站点通常存在配置错误。https://certstream.calidog.io - **SecurityTrails / DNSlytics** — 提供免费额度的商业 DNS 聚合器。 ## 仓库布局 ``` Dockerfile, Makefile — sandbox image (Ubuntu + node + bun + rust + massdns + curl) ai-sandbox/ — same sandbox + claude-code, for AI-assisted iteration scripts/ — the six pipeline steps skim/ — Rust HTTPS prober (status-line + cert verdict) resolvers.txt — curated public DNS resolvers for massdns domain-lists/ — published domain lists produced by this pipeline data/ — pipeline outputs (gitignored, mounted from host) ``` ## 数据集 该仓库还发布了通过运行此 pipeline 生成的域名列表。每个 列表都是一个快照 —— 网络是不断变化的,因此该列表仅在其生成日期 及该日期当天是准确的。 **命名规范:** `YYYY-MM-DD-.txt`,每行一个顶级域名, 无表头,按字母顺序排序。日期前缀是运行扫描的那一天。 **可用列表:** - **`2026-04-26-with-security-txt.txt`**(14,611 个域名) — 在 2026-04-26 探测时,通过有效证书经 HTTPS 提供经过内容验证的 `/.well-known/security.txt` 的域名。方法论:pipeline 以 CrUX 顶级站点列表作为输入运行, `step3` 目标为 `/.well-known/security.txt`,`step6` 使用默认的 `text-file` 验证器 (拒绝空 body、HTML/JSON/PHP 形状、二进制噪声以及无效 UTF-8)。排除了文件存在 但却是带有 200 状态码的 HTML 404 页面的域名。 - **`sample.txt`**(3 个域名) — 一个微型夹具列表(`example.com`、 `google.com`、`github.com`),端到端 CI 工作流使用它对针对 `/robots.txt` 运行的 pipeline 进行冒烟测试。不属于研究产物。 随着新扫描的运行(不同的路径、 不同的日期、不同的域名列表输入),将添加更多列表。要复现任何列表, 使用记录的日期作为 CrUX 快照自己运行 pipeline 即可 —— 给定固定的输入列表,pipeline 是确定性的。 **这些数据集的使用**:参见顶部的[免责声明](#webcensus)。 域名是公开信息;如果你基于这些列表构建衍生工具,请做一个 良好的网络公民(带有标识的 UA、低并发、尊重删除请求)。 ## 引用 如果你在学术或研究工作中使用了本软件,请引用本 仓库。BibTeX 条目如下: ``` @software{webcensus, title = {webcensus: a fast pipeline for path-specific web measurement at scale}, author = {Kirill}, year = {2026}, url = {https://github.com/Kirill89/webcensus} } ``` ## 许可证 [MIT](LICENSE)。按**原样**提供,不做任何保证。使用风险自负 — 参见本 README 顶部的免责声明。 ## 配置选项 - `scripts/step3_probe_status.sh` — 更改 `--path` 以搜寻不同的文件,如果你的网络能够承受,可以提高 `--concurrency`。 - `scripts/step5_curl.sh` — 调整 `--parallel-max`、`--max-filesize`、`--max-time` 以及重试预算。默认值较为保守;如果你的机器和 `ulimit -n` 允许,可以将 `--parallel-max` 提高到 200 以上。 - `scripts/step6_filter.mjs` — 第一个参数用于选择验证器(默认为 `text-file`,也内置了 `json`)。在 `verifiers` 对象中添加新的验证器作为键。 - `resolvers.txt` — 添加/删除解析器;massdns 会在列表中进行负载均衡。
标签:DNS枚举, DNS解析, Docker, GitHub, HTTP请求, Linux取证, massdns, NIDS, Rust, TLS探测, URL路径发现, 主动侦察, 内容验证, 可视化界面, 大规模域名扫描, 子域名发现, 安全文件探测, 安全防御评估, 实时处理, 容器化, 密码管理, 开源项目, 批量抓取, 搜索引擎优化(SEO), 数字取证, 数据可视化, 网站指纹识别, 网络安全工具, 网络流量审计, 网络资产普查, 自动化脚本, 请求拦截, 通知系统