Disane87/badger
GitHub: Disane87/badger
一款自托管的 URL 蜜罐与金丝雀令牌工具,通过创建看似无害的追踪链接来静默记录访问者的详细元数据与行为信息。
Stars: 0 | Forks: 0
[](https://github.com/Disane87/badger/actions/workflows/docker-publish.yml)
[](https://github.com/Disane87/badger/pkgs/container/badger)




[](https://github.com/semantic-release/semantic-release)
[](https://disane87.github.io/badger/)
# 🦡 Badger URL Honeypot
嘿!👋 **Badger** 能把任何链接变成触发器。创建看似无害的 URL,将它们
部署在任何你想监控的地方,一旦有人打开它,你就会确切地知道
*谁*来过以及*带了什么东西*。🕵️♀️✨

把它看作是一个完全由你掌控的 [canary token](https://canarytokens.org/):泄露的凭证
文档、虚假的内部链接、“机密”附件、电子邮件中的跟踪像素。投放一个 Badger
链接,看着元数据滚滚而来。
# ✨ 这东西能做什么?
很高兴你问!这里是精彩的部分:
- 🪤 **四种陷阱类型**:跟踪像素、重定向链接、预览克隆以及完全自定义的虚假页面
- 🔍 **深度元数据捕获**:IP 链、地理位置/ISP/ASN、解析后的浏览器与操作系统、referer、语言、原始标头
- 🤖 **机器人与人类判定**:内置启发式算法可标记自动化客户端(并附带原因!)
- 🪞 **链接预览克隆 (MITM)**:复制任何 URL 的 OpenGraph 卡片,让你的陷阱在 Slack/Discord/X 中以相同的方式展开
- 🎨 **自定义预览构建器**:设计你*自己的*虚假链接预览(图像、标题、描述),并提供实时预览
- 🧭 **选择你的 Payload**:通过重定向将人类引导至别处,或者向他们展示你自己的自定义 HTML 页面
- 📡 **实时 Feed**:跨所有陷阱的每一次点击,流式传输并自动刷新
- 🌍 **地理信息增强**:将原始 IP 转换为国家/城市/ISP(可切换,只要你愿意就可以保持在本地)
- 💾 **零设置存储**:基于文件的持久化,无需照看任何数据库
- 🐳 **一键 Docker**:GHCR 上的预构建镜像,作为一个仅约 170 MB 的轻量级 Alpine 容器发布
- 🦡 **界面赏心悦目**:带有温暖蜂蜜色调的深色、宁静的仪表盘(这里没有吓人的黑客终端)
# 🪤 陷阱类型详解
每个陷阱只是一个你部署在某处的 URL。它被打开时会发生什么取决于其类型:
| 类型 | 访问者看到的内容 | 非常适合 |
|------|------------------------|-----------|
| 👁️ **pixel** | 一张不可见的 1×1 图片 | 电子邮件和文档:嵌入 `
` |
| ↪️ **redirect** | 被转发到一个真实的 URL | 看起来像是一个完全正常的短链接 |
| 🪞 **clone** | 目标的克隆预览,然后转发至该目标 | 让链接的展开效果与真实事物完全一致 |
| 🎨 **custom** | 你手工制作的预览加上重定向 *或* 你自己的 HTML | 暗示一个令人信服的虚假页面 |
| 🎭 **decoy** | 一个友好的“加载中…”页面 | 一个什么都不会暴露的软着陆 |
# 🔍 捕获哪些信息
每一次点击都会记录下有价值的细节:
- 🌐 **完整的 IP 链**:`X-Forwarded-For`、`CF-Connecting-IP`、`X-Real-IP` 以及 socket 地址
- 📍 **地理与网络信息**:国家、城市、地区、ISP、组织、ASN(通过 [ip-api.com](https://ip-api.com),可关闭)
- 🧭 **客户端指纹**:浏览器、版本、操作系统、设备、引擎(从 User-Agent 解析)
- 🗣️ **标头与提示**:referer、`Accept-Language` 以及完整的原始请求标头
- 🤖 **机器人判定**:人类还是机器人,以及做出该决定的启发式原因
# 📦 安装
有两种简单的方法可以开始:获取容器,或从源码运行它。🎉
# 🐳 Docker(最简单的方式)
每次推送到默认分支和版本标签时,镜像都会自动构建并推送到 **GitHub Container Registry**。只需拉取并运行:
```
docker run -d --name badger \
-p 3000:3000 \
-e NUXT_PUBLIC_BASE_URL=https://badger.example.com \
-e BADGER_DASHBOARD_TOKEN="$(openssl rand -hex 32)" \
-v badger-data:/app/.data \
ghcr.io/disane87/badger:latest
```
然后打开 **http://localhost:3000** 就可以开始设置陷阱了!🦡
- 🔌 监听 `:3000` 端口(使用 `-e PORT=` 更改),绑定 `0.0.0.0`,以非 root 用户身份运行
- 💾 陷阱和点击数据存放在 `/app/.data` 中,因此请挂载一个卷以便在重启后保留数据
- ❤️ 内置的健康检查会请求 `/api/traps`,以便你的编排器知道它何时准备就绪
- 🏷️ 可用标签:`latest`、`sha-`,以及 `v*` 版本上的 semver (`1.2.3`, `1.2`)
更愿意自己构建它?
```
docker build -t badger .
docker run -d -p 3000:3000 -v badger-data:/app/.data badger
```
# 🚀 快速开始(从源码)
准备好了吗?这里是开发环境设置:
```
npm install
npm run dev
```
就这样!🎉 打开 **http://localhost:3000**。
要在没有 Docker 的情况下为生产环境构建吗?
```
npm run build
node .output/server/index.mjs
```
# ⚙️ 配置
只需几个环境变量即可:
| 变量 | 默认值 | 作用 |
|----------|---------|--------------|
| `NUXT_PUBLIC_BASE_URL` | *(空)* | 用于你的跟踪链接的公共基础 URL。将其设置为你的域名(例如 `https://badger.example.com`),以便复制的 URL 指向正确的位置。如果为空,则回退到浏览器的当前源。 |
| `NUXT_GEO_LOOKUP` | `true` | 通过 ip-api.com 进行出站 IP 到地理信息的增强。设置为 `false` 可保持 100% 本地化且无任何出站调用。 |
| `BADGER_DASHBOARD_TOKEN` | *(未设置)* | 保护每个 `/api/*` 仪表盘端点的共享密钥。**必填** — 如果未设置,服务器将对所有 API 调用返回 `503`。请参阅[身份验证](#-authentication)。 |
| `BADGER_AUTH_DISABLED` | *(未设置)* | 设置为 `1` 可完全绕过 `BADGER_DASHBOARD_TOKEN`。**仅限本地开发使用 — 切勿在生产环境中设置。** |
| `PORT` | `3000` | 服务器监听的端口。 |
| `HOST` | `0.0.0.0` | 绑定地址。 |
这里还有一个可直接复制的 [`.env.example`](.env.example)。📝
# 🔐 身份验证
每个 `/api/*` 端点都会传输敏感的 Honeypot 数据 — 访问者 IP、请求标头、其浏览器泄露的 cookie 以及完整的陷阱配置。因此,Badger 将整个仪表盘 API 置于
一个单一的共享 token 之后。这是刻意为之的简单设计:一个密钥,没有用户账户,也没有 session 存储。🗝️
## 设置 token
生成一串长且随机的字符,然后通过 `BADGER_DASHBOARD_TOKEN` 将其交给服务器:
```
# 生成
openssl rand -hex 32
# → 将结果放入你的 .env、docker-compose 或 -e flag 中
```
## 客户端如何发送它
中间件可以从以下任何位置接受 token(以首个匹配项为准):
| 位置 | 样式 |
|-------|--------------|
| 🏷️ 标头 | `Authorization: Bearer ` |
| 🍪 Cookie | `badger_token=` |
| 🔗 查询 | `?token=`(方便快速使用 `curl`,请避免在你分享的 URL 中使用) |
针对正在运行的实例进行快速冒烟测试:
```
curl -H "Authorization: Bearer $BADGER_DASHBOARD_TOKEN" http://localhost:3000/api/traps
```
## 反向代理注入(推荐用于生产环境)
如今在浏览器中使用仪表盘的最简洁方式是让你的反向代理为你附加
标头。使用 nginx 的示例:
```
location / {
proxy_pass http://badger:3000;
proxy_set_header Authorization "Bearer $HONEY_TOKEN_FROM_NGINX_ENV";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
```
…或者 Caddy:
```
badger.example.com {
reverse_proxy badger:3000 {
header_up Authorization "Bearer {env.BADGER_DASHBOARD_TOKEN}"
}
}
```
这样浏览器就永远不需要知道密钥。如果你想要纵深防御,可以将其与 VPN 访问或 IP 白名单结合使用。🛡️
## 本地开发
针对全新检出运行 `npm run dev` 会在每次 API 调用时返回 503。有两个选项:
```
# 1. 使用一次性 token 运行(模拟生产环境行为)
BADGER_DASHBOARD_TOKEN=dev-only npm run dev
# 2. 完全跳过 auth。速度快,但切勿在生产环境中使用。
BADGER_AUTH_DISABLED=1 npm run dev
```
# 🎨 仪表盘
Badger 附带了三个友好的界面:
- 🪤 **Traps**:你的指挥中心。创建陷阱,复制其 URL,一目了然地查看点击次数。
- 📡 **Live Feed**:跨所有陷阱的每一位近期访问者,自动刷新,让你无需动手。
- 🔎 **Trap Detail**:带有可展开元数据的完整点击时间线,以及用于 clone/custom 陷阱的链接预览卡片。
| 🔎 陷阱详情 | 📡 实时 Feed |
|----------------|--------------|
|  |  |
想设计一个虚假预览?**自定义预览构建器**允许你输入标题、描述和
图像 URL,并实时观看社交卡片预览的更新,然后选择是将人类重定向
还是展示你自己的 HTML。🪄

# 🛠️ 技术栈
用这些好东西构建:
- ⚡ **[Nuxt 4](https://nuxt.com) + [Vue 3](https://vuejs.org)**:将 SSR 应用与 Nitro 服务器合二为一
- 🎀 **[@nuxt/icon](https://github.com/nuxt/icon)** 搭配 [Lucide](https://lucide.dev) 图标集(本地打包,无 CDN)
- 🧩 **[unstorage](https://unstorage.unjs.io)**:基于文件的持久化,无需安装其他任何东西
- 🐳 **多阶段 Docker** 加上 GitHub Actions 推送至 GHCR
# ⚠️ 法律与道德声明
Badger 是一种**防御性**工具。仅在属于你自己的或已获得明确授权进行监控的资产和网络上
部署它。地理查询会将访问者 IP 发送给第三方 API(如果对此有顾虑请禁用),`clone` 和
`custom` 陷阱可以复制或伪造链接预览,而 `custom` 陷阱会逐字渲染操作者编写的 HTML。请勿使用这些功能来欺骗
或冒充第三方,因为这已经跨越了网络钓鱼的界限,并且在大多数地方都是非法的。🙏
# 🚀 发布
版本控制通过 [semantic-release](https://semantic-release.gitbook.io/) 完全自动化。每一次
向 `main` 的推送都会被分析,而你的 [Conventional Commits](https://www.conventionalcommits.org/)
将决定接下来会发生什么:
- 🐛 `fix:` → 补丁发布 (1.0.**1**)
- ✨ `feat:` → 次要发布 (1.**1**.0)
- 💥 `feat!:` 或带有 `BREAKING CHANGE:` 的页脚 → 主要发布 (**2**.0.0)
- 🧹 `chore:`、`docs:`、`refactor:`、`test:` 等 → 无发布
当进行发布时,流水线会自动:
1. 🏷️ 标记提交并创建一个带有生成说明的 **GitHub Release**
2. 📝 更新 [`CHANGELOG.md`](CHANGELOG.md) 和 `package.json` 中的版本号
3. 🐳 构建并将 Docker 镜像推送到 GHCR,标签为 `:x.y.z`、`:x.y` 和 `:latest`
所以,只需写出好的提交信息,把无聊的工作交给机器人吧!🤖✨
# 📄 许可证
[MIT](LICENSE)。请用它做些好事。
` |
| ↪️ **redirect** | 被转发到一个真实的 URL | 看起来像是一个完全正常的短链接 |
| 🪞 **clone** | 目标的克隆预览,然后转发至该目标 | 让链接的展开效果与真实事物完全一致 |
| 🎨 **custom** | 你手工制作的预览加上重定向 *或* 你自己的 HTML | 暗示一个令人信服的虚假页面 |
| 🎭 **decoy** | 一个友好的“加载中…”页面 | 一个什么都不会暴露的软着陆 |
# 🔍 捕获哪些信息
每一次点击都会记录下有价值的细节:
- 🌐 **完整的 IP 链**:`X-Forwarded-For`、`CF-Connecting-IP`、`X-Real-IP` 以及 socket 地址
- 📍 **地理与网络信息**:国家、城市、地区、ISP、组织、ASN(通过 [ip-api.com](https://ip-api.com),可关闭)
- 🧭 **客户端指纹**:浏览器、版本、操作系统、设备、引擎(从 User-Agent 解析)
- 🗣️ **标头与提示**:referer、`Accept-Language` 以及完整的原始请求标头
- 🤖 **机器人判定**:人类还是机器人,以及做出该决定的启发式原因
# 📦 安装
有两种简单的方法可以开始:获取容器,或从源码运行它。🎉
# 🐳 Docker(最简单的方式)
每次推送到默认分支和版本标签时,镜像都会自动构建并推送到 **GitHub Container Registry**。只需拉取并运行:
```
docker run -d --name badger \
-p 3000:3000 \
-e NUXT_PUBLIC_BASE_URL=https://badger.example.com \
-e BADGER_DASHBOARD_TOKEN="$(openssl rand -hex 32)" \
-v badger-data:/app/.data \
ghcr.io/disane87/badger:latest
```
然后打开 **http://localhost:3000** 就可以开始设置陷阱了!🦡
- 🔌 监听 `:3000` 端口(使用 `-e PORT=` 更改),绑定 `0.0.0.0`,以非 root 用户身份运行
- 💾 陷阱和点击数据存放在 `/app/.data` 中,因此请挂载一个卷以便在重启后保留数据
- ❤️ 内置的健康检查会请求 `/api/traps`,以便你的编排器知道它何时准备就绪
- 🏷️ 可用标签:`latest`、`sha-标签:BOF, Docker, Nuxt, StruQ, Vue, 后端开发, 安全防御评估, 文件系统扫描, 欺骗防御, 蜜罐, 证书利用, 请求拦截, 追踪