pathsec/Apparition
GitHub: pathsec/Apparition
一个容器化的浏览器中间人平台,通过 noVNC 向目标提供隔离的 Firefox 浏览会话,支持活动管理、Token 邀请和浏览器配置文件导出。
Stars: 0 | Forks: 0
# Apparition
Apparition 是一个活动驱动、容器化的中间人浏览器平台,通过链接向接收者提供临时、隔离的浏览会话。当用户访问 /join/ 时,Apparition 会启动一个专用的 Docker 容器,该容器在无头 XFCE 桌面中运行 Firefox,并通过 noVNC 进行流式传输,提供全屏的“真实浏览器”体验,而不会暴露操作主机或其他会话。Node/Express 控制服务器负责编排会话的创建和拆除,执行活动生命周期和完成规则,并在 SQLite 中记录活动/token/会话状态。
会话可以在超时、手动拆除或定义的完成条件满足后自动结束——随后容器将被销毁,用户将被重定向到配置的目的地。可选地,用户可以继续浏览,直到达到活动定义的时间限制。当满足完成条件时,可以从管理控制台下载会话的浏览器配置文件;否则,配置文件将随时可在会话视图中下载,以供审查和报告。
` 链接。
4. Apparition 启动一个 Docker 容器,通过 noVNC 在无头 XFCE 桌面中运行 Firefox。
5. 用户看到全屏浏览器。当会话结束时(超时、完成触发或手动拆除),容器将被销毁,用户将被重定向。
## 架构
```
┌─────────────────────────┐
│ nginx │ (optional, recommended)
│ TLS termination + │
│ WebSocket proxy │
└────────────┬────────────┘
│ :443
┌────────────▼────────────┐
│ Apparition (Node) │ :3000
│ Express + SQLite │
│ Admin UI + API │
└────────────┬────────────┘
│ Docker socket
┌──────────────────┼──────────────────┐
│ │ │
┌──────────▼──────┐ ┌────────▼──────┐ ┌───────▼───────┐
│ novnc-session-1 │ │novnc-session-2│ │novnc-session-3│
│ Firefox + noVNC │ │Firefox + noVNC│ │Firefox + noVNC│
│ port 6900 │ │ port 6901 │ │ port 6902 │
└─────────────────┘ └───────────────┘ └───────────────┘
```
- **控制服务器 (Control server)** — Node.js/Express 应用程序。管理活动、Token、会话和管理仪表板。通过 Docker socket 生成和拆除兄弟容器。
- **noVNC 容器** — Docker 兄弟容器,每个容器运行 XFCE + Firefox + noVNC,绑定到唯一的主机端口(默认为 6900–6999)。每个容器通过环境变量接收会话上下文。
- **SQLite** — 存储活动、邀请 Token、会话、电子邮件历史和提交内容。
- **nginx**(生产环境推荐)— 终止 TLS,代理所有流量,包括 noVNC 的 WebSocket 升级。
## 前置条件
- **Docker Engine** 20.10+ 和 **Docker Compose** v2+
- Linux 主机(推荐 Debian/Ubuntu 或 RHEL/Fedora)
- Node.js 18+(仅在本地开发时需要 — Docker 负责生产环境)
-(生产环境)用于 TLS 的 nginx + certbot
## 安装
### 1. 克隆仓库
```
git clone apparition
cd apparition
```
### 2. 配置环境变量
```
cp .env.example .env
```
打开 `.env` 并至少设置:
| Variable | What to set |
|---|---
| `SESSION_SECRET` | 一个长的随机字符串 — 运行 `openssl rand -hex 64` |
| `JWT_SECRET` | 另一个不同的长随机字符串 — 运行 `openssl rand -hex 64` |
| `CONTROL_HOST` | 此服务器的公共 URL,例如 `https://example.com` |
| `CONTAINER_HOST` | 容器回调的内部 URL — `http://host.docker.internal:3000` |
| `NOVNC_HOST` | noVNC 端口可访问的主机名 — 通常为 `host.docker.internal` |
### 3. 构建 Kiosk 镜像
在启动任何会话之前,必须构建自定义的 noVNC/Firefox 容器镜像:
```
docker compose build novnc-kiosk
```
这会构建 `./novnc-container` 并将其在本地标记为 `novnc-kiosk`。只需运行一次,或者在更改 `novnc-container/` 后再次运行。
### 4. 启动控制服务器
```
docker compose up -d
```
应用程序在端口 3000 上运行。使用以下命令检查日志:
```
docker compose logs -f app
```
### 5. 创建管理员账户
```
docker compose exec app node src/scripts/create-admin.js
```
按照提示设置用户名和密码。这只需运行一次。
### 6. 打开管理面板
导航到 `http://localhost:3000/admin/login`(或您的域名)。
## 生产环境设置 (nginx + TLS)
### 安装并配置 nginx
复制包含的 nginx 配置:
```
sudo cp nginx/novnc-manager.conf /etc/nginx/sites-available/apparition
```
在配置文件中将 `YOUR_DOMAIN` 替换为您的实际域名:
```
sudo sed -i 's/YOUR_DOMAIN/example.com/g' /etc/nginx/sites-available/apparition
```
### 获取 TLS 证书
```
sudo certbot --nginx -d example.com
```
### 启用站点
```
sudo ln -s /etc/nginx/sites-available/apparition /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
```
### 为生产环境更新 `.env`
```
CONTROL_HOST=https://example.com
CONTAINER_HOST=http://host.docker.internal:3000
COOKIE_SECURE=true
```
更改 `.env` 后重启应用程序:
```
docker compose up -d
```
## 环境变量
有关完整的注释模板,请参阅 `.env.example`。
### 必需项
| Variable | Description |
|---|---
| `SESSION_SECRET` | Express 会话签名的密钥 |
| `JWT_SECRET` | 容器 JWT 签名的密钥(必须与 `SESSION_SECRET` 不同)|
### 服务器
| Variable | Default | Description |
|---|---|---|
| `PORT` | `3000` | Node 服务器监听的端口 |
| `CONTROL_HOST` | — | 公共基础 URL(用于邀请链接和电子邮件)|
| `CONTAINER_HOST` | `http://host.docker.internal:3000` | 容器用于回调的内部 URL |
| `NOVNC_HOST` | `host.docker.internal` | noVNC 容器端口可访问的主机/IP |
| `COOKIE_SECURE` | `false` | 通过 HTTPS 提供服务时设置为 `true` |
| `JOIN_PATH` | `join` | 邀请链接的 URL 段(例如 `/join/`)|
| `DB_PATH` | `/data/app.db` | SQLite 数据库文件的路径 |
### Docker / 容器
| Variable | Default | Description |
|---|---|---|
| `NOVNC_IMAGE` | `novnc-kiosk` | 用于会话容器的 Docker 镜像 |
| `NOVNC_PORT_START` | `6900` | noVNC 容器主机端口池的起始端口 |
| `NOVNC_PORT_END` | `6999` | 主机端口池的结束端口 |
| `CONTAINER_NETWORK` | `bridge` | 容器连接到的 Docker 网络 |
| `CONTAINER_MEMORY_LIMIT` | `1073741824` | 每个容器的内存限制(字节)(默认 1 GB)|
| `CONTAINER_CPU_LIMIT` | `1000000000` | 每个容器的 CPU 限制(纳秒 CPU)(默认 1 CPU)|
| `CLEANUP_INTERVAL_MS` | `60000` | 清理作业运行的频率(毫秒)|
### SMTP / 电子邮件
| Variable | Default | Description |
|---|---|---|
| `SMTP_HOST` | — | SMTP 服务器主机名 |
| `SMTP_PORT` | `587` | SMTP 端口 |
| `SMTP_SECURE` | `false` | 使用 SMTPS(端口 465 时设置为 `true`)|
| `SMTP_USER` | — | SMTP 用户名或 API 密钥 |
| `SMTP_PASS` | — | SMTP 密码或密钥 |
| `SMTP_FROM` | — | 发件人地址 |
| `SMTP_FROM_NAME` | `Apparition` | 外发电子邮件的显示名称 |
SMTP 设置也可以通过管理设置 UI 进行配置。环境变量优先于 UI 值。
### 可选:直接 TLS(不带 nginx)
| Variable | Description |
|---|---
| `SSL_KEY` | TLS 私钥的路径 — 直接在 Node 上启用 HTTPS |
| `SSL_CERT` | TLS 证书的路径 |
## 活动 (Campaigns)
活动是一组邀请 Token 继承的命名配置。每个活动定义:
| Field | Description |
|---|---
| **Name** | 活动的内部标签 |
| **Start URL** | 会话开始时 Firefox 打开的 URL |
| **Lifetime** | 会话持续时间(分钟)— 容器将在此时间后拆除 |
| **Redirect URL** | 会话结束后用户被发送到的位置 |
| **Slug** | 查看器的清晰 URL 前缀(例如 `/my-campaign/`)|
| **Favicon URL** | 查看器中显示的标签页图标(根据用户浏览自动更新)|
| **Completion URL** | 当 Firefox 访问此 URL 时,触发会话完成 |
| **Completion Cookie** | 当设置此 Cookie 名称时,触发会话完成 |
| **After Completion** | `redirect`(默认)拆除容器;`keep_alive` 保持其运行 |
| **Show Loading Page** | 是否在容器启动时显示“Starting...”页面 |
## 邀请 Token
每个邀请 Token 映射到一个唯一的 `/join/` URL。Token 可以:
- 从活动详情页面单独生成
- 批量生成用于电子邮件分发
- 通过内置电子邮件编辑器发送
当使用 Token 时:
1. 启动一个 Docker 容器(`novnc-session-`)
2. Firefox 打开活动的起始 URL
3. 加载页面轮询控制服务器,直到 noVNC 端口接受连接
4. 查看器渲染一个全屏 iframe,显示 Firefox 会话
查看器每 3 秒轮询一次服务器,以将浏览器标签页标题和图标与 Firefox 的当前页面同步。
## 管理面板
位于 `/admin` 的管理面板提供:
- **仪表板** — 实时会话计数和最近活动
- **活动** — 创建和管理活动,查看 Token 和会话日志
- **邀请链接** — 管理单个 Token,查看点击和启动统计
- **电子邮件** — 撰写和发送带有嵌入邀请链接的活动电子邮件
- **会话** — 完整的会话日志,包含提交数据和 Firefox 配置文件下载
- **设置** — 配置 SMTP 和 Cloudflare Turnstile
## 机器人防护
要在加入页面上要求 CAPTCHA 验证,请在 `.env` 中添加或通过设置 UI 进行配置:
```
TURNSTILE_SITE_KEY=your-site-key
TURNSTILE_SECRET_KEY=your-secret-key
```
配置后,加入页面会在允许会话开始之前渲染一个 Turnstile 小部件。
## 开发
```
npm install
cp .env.example .env # edit for local config
npm run dev # starts with nodemon hot-reload
```
服务器在 `http://localhost:3000` 上运行。Docker 必须正在运行且可访问,以便进行容器管理。
## 安全说明
- 应用程序容器挂载 Docker socket(`/var/run/docker.sock`),这授予了对主机的 root 等效访问权限。在生产环境中,考虑使用 [Tecnativa/docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) 来限制允许哪些 Docker API 调用。
- 会话 Cookie 是 `httpOnly`、`sameSite: lax` 的,当 `COOKIE_SECURE=true` 时为 `secure`。
- 所有容器到服务器的回调都通过短期、会话范围的 JWT 进行身份验证。
- 加入和会话端点应用了速率限制。
- `docker-compose.yml` 中的 `security_opt: label:disable` 在 Fedora/RHEL 上是必需的,以允许在 SELinux 下访问 Docker socket。它仅影响应用程序容器的标签限制。
标签:BITM, Docker, ESC8, Express, Firefox, GNU通用公共许可证, MITM代理, NIDS, Node.js, noVNC, RBIS, SQLite, XFCE, 一次性链接, 会话录制, 匿名浏览, 安全防御评估, 容器化, 攻击模拟, 浏览器中间人, 社会工程学, 网络安全, 自定义脚本, 请求拦截, 远程浏览器隔离, 隐私保护, 隔离环境, 驱动签名利用