BenJonesVA/nullvault
GitHub: BenJonesVA/nullvault
一款自托管的蜜罐链接追踪器,通过伪装的机密页面记录访问者的 IP、地理位置和设备信息,用于反诈骗与开源情报收集。
Stars: 2 | Forks: 0
# 🔒 NullVault
[](LICENSE)
[](package.json)
[](docker-compose.yml)
[](https://github.com/rehatiel/nullvault/pulls)
一个自托管的蜜罐链接追踪器。创建一个看似机密的 URL,将其分享给目标,并在被打开的瞬间收到通知——包含地理位置、设备信息、私有控制面板以及可选的 webhook 告警。
专为反诈骗(scam baiting)、OSINT 以及抓捕对敏感材料的未授权访问而构建。
**[在 YouTube 上观看设置与功能演示](https://youtu.be/lQNXXxNvbOo)**
## 截图
### 创建链接
| 创建表单 | 已生成的链接 |
|---|---|
|  |  |
### 目标所见的页面
| 银行诱饵 | 机密已揭晓 |
|---|---|
|  |  |
### 私有控制面板

| 访问时间线 | IP / OSINT 查询 | 设备信息明细 |
|---|---|---|
|  |  |  |
## 功能
- **欺骗性模板** — 公开页面看起来像是一个通用的机密分享页、银行门户、加密货币钱包、发票、公司文档或文档站点
- **阅后即焚开关** — 可选择在首次阅读后销毁机密,或将其保留以进行持续监控
- **完整的访问日志** — 每次访问都会捕获 IP、城市/州/国家、ISP、浏览器、操作系统、来源页(referrer)和时间戳
- **私有控制面板** — 统计卡片、活动图表、世界地图、美国各州热力图、设备明细、IP 查询、带有 CSV 导出功能的原始日志表
- **Webhook 告警** — 从控制面板配置 Discord webhook 或任何 HTTP endpoint;内置测试 ping 功能
- **位置追踪** — 可选择在揭示机密前要求进行 GPS 确认;移动端访问者将被提示分享位置
- **运行时零外部请求** — 字体、Chart.js 和地图 SVG 均为自托管;没有 CDN 调用,没有第三方分析
- **严格的 CSP** — `script-src 'self'`、`style-src 'self'`、`default-src 'none'`;零内联样式或脚本
- **Docker 优先** — 只需一条 `docker compose up -d` 命令即可部署;SQLite 持久化存储在具名 volume 中
## 快速开始
### 1. 克隆并配置
```
git clone https://github.com/rehatiel/nullvault.git
cd nullvault
cp .env.example .env
```
打开 `.env` 并至少设置:
```
BASE_URL=https://your-domain.com
CREATION_SECRET=your-long-random-secret
```
生成一个强密码:
```
openssl rand -hex 32
```
### 2. 部署
```
docker compose up -d
```
应用监听 `3000` 端口。请在前面放置 Nginx、Caddy 或 Cloudflare Tunnel。
访问 `https://your-domain.com`,从 Web UI 创建你的第一个蜜罐链接。
## 用法
### Web UI
访问主页以使用表单创建链接。选项:
| 字段 | 描述 |
|---|---|
| **内容** | 访问者在揭示时看到的机密文本(最多 4,096 个字符) |
| **模板** | 向访问者展示的视觉诱饵皮肤 |
| **过期时间** | 距离链接停止工作的天数(`0` = 永不) |
| **阅后即焚** | 在首次成功揭示后销毁机密 |
| **要求位置** | 在揭示机密前提示访问者提供 GPS |
创建后,你将收到一个用于分享的 **公开 URL** 和一个需要收藏的 **控制 URL** —— 该控制 URL 就是你的私有仪表板。
### 模板
| 值 | 外观 |
|---|---|
| `default` | 通用的 NullVault 安全机密页面 |
| `banking` | “SecureDoc Portal” — 公司文档投递 |
| `crypto` | “WalletVault” — 加密货币钱包助记词查看器 |
| `invoice` | 发票文档查看器 |
| `corporate` | 公司内部文档门户 |
| `docs` | 通用文档/文件分享 |
### 控制面板
每个链接在 `/s//control` 都有一个私有仪表板:
| 标签页 | 内容 |
|---|---|
| **概览** | 统计卡片、最近活动时间线、世界地图、美国各州热力图 |
| **时间线** | 包含事件类型、IP、位置的完整按时间顺序排列的日志 |
| **设备** | 根据 User-Agent 字符串得出的浏览器和操作系统明细 |
| **IP 地址** | 带有位置、ISP 和 IPInfo 查询链接的去重 IP |
| **原始日志** | 带有 CSV 导出功能的完整表格 |
| **设置** | Webhook URL、位置要求开关 —— 可随时设置、更新、清除或测试 |
### 地图
- **世界地图** — 高亮显示有访问记录的国家;鼠标悬停可查看名称 + 数量
- **美国各州热力图** — 当检测到美国流量时自动出现;各州颜色按照 4 级梯度(琥珀色 → 红色)着色,相对于最活跃的州
### Webhook 告警
从 **设置** 标签页进行配置。格式会被自动检测:
- **Discord** — 包含事件类型、IP、位置、user agent、来源页的丰富 embed
- **通用 HTTP** — JSON POST,包含 `event`、`publicUrl`、`ip`、`location`、`userAgent`、`referer`、`timestamp`
**发送测试 Ping** 按钮会触发一个带有 `test: true` 的真实请求,以验证送达情况。
## API
所有 endpoint 均返回 JSON。创建链接需要提供与 `CREATION_SECRET` 匹配的 `X-Creation-Secret` header。
### `POST /create`
**Headers:**
```
X-Creation-Secret:
Content-Type: application/json
```
**Body:**
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `content` | string | ✅ | 最多 4,096 个字符 |
| `template` | string | | `default`、`banking`、`crypto`、`invoice`、`corporate`、`docs` |
| `expiryDays` | number | | `0` = 永不;默认为 `DEFAULT_EXPIRY_DAYS` |
| `burnOnReveal` | boolean | | `true` = 一次性揭示 |
**响应 `201`:**
```
{
"publicUrl": "https://your-domain.com/s/",
"controlUrl": "https://your-domain.com/s//control",
"expiresAt": 1234567890
}
```
### 其他 endpoint
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/s/:token` | 公开蜜罐页面 |
| `POST` | `/s/:token/reveal` | 揭示机密(由公开页面调用) |
| `GET` | `/s/:token/control` | 私有控制面板 |
| `POST` | `/s/:token/webhook` | 更新 webhook URL(`{ "webhookUrl": "..." }` 或 `null` 以清除) |
| `POST` | `/s/:token/webhook/test` | 触发测试 ping |
| `GET` | `/health` | 返回 `{ "status": "ok" }` |
## 配置
| 变量 | 默认值 | 描述 |
|---|---|---|
| `BASE_URL` | — | **必填。** 完整的公开 URL,无尾随斜杠 |
| `CREATION_SECRET` | — | **必填。** `/create` 的 `X-Creation-Secret` header 值 |
| `PORT` | `3000` | 监听端口 |
| `TRUST_PROXY` | `1` | Express 的 trust-proxy 深度 |
| `DEFAULT_EXPIRY_DAYS` | `30` | 默认链接生命周期(以天为单位) |
| `RETENTION_DAYS` | `30` | 访问日志保留天数 |
| `RATE_LIMIT_WINDOW_MS` | `60000` | 速率限制窗口(毫秒) |
| `RATE_LIMIT_MAX` | `20` | 每个 IP 在每个窗口的最大请求数 |
| `DB_PATH` | `/app/data/honeypot.db` | 容器内的 SQLite 路径 |
## 反向代理
### Nginx
```
server {
listen 443 ssl;
server_name your-domain.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
### Caddy
```
your-domain.com {
reverse_proxy localhost:3000
}
```
### Cloudflare Tunnel
设置 `TRUST_PROXY=1`。NullVault 会自动从 `CF-Connecting-IP` 读取真实 IP。
## 更新
```
git pull
docker compose up -d --build
```
数据库 schema 会在启动时自动迁移 —— 无需手动操作。
## 安全说明
- `controlUrl` 是仪表板的唯一访问控制手段 —— 请将其视为密码妥善保管
- `CREATION_SECRET` 用于保护链接的创建;请使用较长且随机的值
- 地理位置使用内置的 `geoip-lite` 离线数据库 —— 无出站 IP 查询
- Helmet.js 强制执行严格的 CSP:无内联脚本,无内联样式,无外部资源
- SQLite 启用了 WAL 模式,以确保在流量高峰期能够安全地进行并发读取
## 技术栈
| 层级 | 技术 |
|---|---|
| 运行时 | Node.js 20 (Alpine) |
| Web 框架 | Express 4 |
| 数据库 | 通过 `better-sqlite3` 实现的 SQLite |
| 模板 | Nunjucks |
| 地理位置 | `geoip-lite`(完全离线) |
| 安全 header | Helmet.js |
| 地图 | Natural Earth + US Atlas TopoJSON(预渲染 SVG) |
| 图表 | Chart.js 4(自托管) |
| 字体 | IBM Plex Sans/Mono(自托管 WOFF2) |
## 收集的数据
本项目有意限制了数据收集。记录的元数据包括:
- IP 地址、时间戳和请求路径
- User-Agent 字符串和 HTTP 来源页(referrer)
- 标准 HTTP header(`Accept-Language`、`Sec-CH-UA`、`Sec-Fetch-Site`)
- 大致地理位置(通过离线数据库获取的城市 / 地区 / 国家)
- GPS 坐标(仅在访问者明确授予浏览器位置权限时)
该应用程序不执行客户端漏洞利用,不使用侵入性指纹追踪,不进行跨会话用户追踪,也不试图对访问者进行去匿名化处理。
## ⚠️ 重要免责声明
本软件仅供**教育和研究目的**使用。
使用本项目即表示你同意:
- 你有责任遵守所有适用的地方、州和国际法律
- 你不会将本软件用于骚扰、人肉搜索、报复或未经授权的监控
- 你理解基于 IP 的地理位置是近似且不可靠的
- 你不会试图使用本软件识别、追踪或伤害个人
- 作者和贡献者对滥用行为不承担任何责任
**这不是**黑客工具、人肉搜索平台、凭证收割器或执法解决方案。
## 许可证
MIT — 查看 [LICENSE](LICENSE)。
标签:BOF, Docker, GNU通用公共许可证, Node.js, 安全研发, 安全防御评估, 欺骗防御, 网络情报, 自定义脚本, 蜜罐, 证书利用, 请求拦截, 链接追踪