Files
xingrin/docs/wordlist-architecture.md
2025-12-25 16:02:55 +08:00

254 lines
7.5 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 字典文件管理架构
本文档介绍 XingRin 中字典文件的存储、同步和使用机制。
## 目录结构
```
/opt/xingrin/wordlists/
├── common.txt # 通用字典
├── subdomains.txt # 子域名字典
├── directories.txt # 目录字典
└── ...
```
## 一、存储位置
| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `WORDLISTS_BASE_PATH` | `/opt/xingrin/wordlists` | 字典文件存储目录 |
## 二、数据模型
```
Wordlist
├── id # 字典 ID
├── name # 字典名称(唯一,用于查询)
├── description # 描述
├── file_path # 文件绝对路径
├── file_size # 文件大小(字节)
├── line_count # 行数
└── file_hash # SHA256 哈希值(用于校验)
```
## 三、Server 端上传流程
1. 用户在前端上传字典文件
2. `WordlistService.create_wordlist()` 处理:
- 保存文件到 `WORDLISTS_BASE_PATH` 目录
- 计算 SHA256 哈希值
- 统计文件大小和行数
- 创建数据库记录
```mermaid
flowchart TB
subgraph SERVER["🖥️ Server 容器"]
direction TB
subgraph UI["前端 UI"]
direction LR
UPLOAD["📤 上传字典<br/>选择文件"]
EDIT["✏️ 编辑内容<br/>在线修改"]
DELETE["🗑️ 删除字典"]
end
UPLOAD --> API
EDIT --> API
subgraph API["API 层"]
VIEWSET["WordlistViewSet<br/>POST /api/wordlists/<br/>PUT .../content/"]
end
API --> SERVICE
subgraph SERVICE["业务逻辑层"]
CREATE["create_wordlist()<br/>创建字典"]
UPDATE["update_wordlist_content()<br/>更新字典内容"]
end
CREATE --> PROCESS
UPDATE --> PROCESS
subgraph PROCESS["处理流程"]
direction TB
STEP1["1⃣ 保存文件到<br/>/opt/xingrin/wordlists/"]
STEP2["2⃣ 计算 SHA256 哈希值"]
STEP3["3⃣ 统计文件大小和行数"]
STEP4["4⃣ 创建/更新数据库记录"]
STEP1 --> STEP2
STEP2 --> STEP3
STEP3 --> STEP4
end
STEP4 --> DB
STEP1 --> FS
subgraph DB["💾 PostgreSQL 数据库"]
DBRECORD["INSERT INTO wordlist<br/>name: 'subdomains'<br/>file_path: '/opt/xingrin/wordlists/subdomains.txt'<br/>file_size: 1024000<br/>line_count: 50000<br/>file_hash: 'sha256...'"]
end
subgraph FS["📁 文件系统"]
FILES["/opt/xingrin/wordlists/<br/>├── common.txt<br/>├── subdomains.txt<br/>└── directories.txt"]
end
end
style SERVER fill:#e6f3ff
style UI fill:#fff4e6
style API fill:#f0f0f0
style SERVICE fill:#d4edda
style PROCESS fill:#ffe6f0
style DB fill:#cce5ff
style FS fill:#e2e3e5
```
## 四、Worker 端获取流程
Worker 执行扫描任务时,通过 `ensure_wordlist_local()` 获取字典:
1. 根据字典名称查询数据库,获取 `file_path``file_hash`
2. 检查本地是否存在字典文件
- 存在且 hash 匹配:直接使用
- 存在但 hash 不匹配:重新下载
- 不存在:从 Server API 下载
3. 下载地址:`GET /api/wordlists/download/?wordlist=<name>`
4. 返回本地字典文件路径
```mermaid
flowchart TB
subgraph WORKER["🔧 Worker 容器"]
direction TB
START["🎯 扫描任务<br/>需要字典"]
START --> ENSURE
ENSURE["ensure_wordlist_local()<br/>参数: wordlist_name"]
ENSURE --> QUERY
QUERY["📊 查询 PostgreSQL<br/>获取 file_path, file_hash"]
QUERY --> CHECK
CHECK{"🔍 检查本地文件<br/>/opt/xingrin/wordlists/"}
CHECK -->|不存在| DOWNLOAD
CHECK -->|存在| HASH
HASH["🔐 计算本地文件 SHA256<br/>与数据库 hash 比较"]
HASH -->|一致| USE
HASH -->|不一致| DOWNLOAD
DOWNLOAD["📥 从 Server API 下载<br/>GET /api/wordlists/download/?wordlist=name"]
DOWNLOAD --> SERVER
SERVER["🌐 HTTP Request"]
SERVER -.请求.-> API["Server (Django)<br/>返回文件内容"]
API -.响应.-> SERVER
SERVER --> SAVE
SAVE["💾 保存到本地<br/>/opt/xingrin/wordlists/filename"]
SAVE --> RETURN
USE["✅ 直接使用"] --> RETURN
RETURN["📂 返回本地字典文件路径<br/>/opt/xingrin/wordlists/subdomains.txt"]
RETURN --> EXEC
EXEC["🚀 执行扫描工具<br/>puredns bruteforce -w /opt/xingrin/wordlists/xxx.txt"]
end
style WORKER fill:#e6f3ff
style START fill:#fff4e6
style CHECK fill:#ffe6f0
style HASH fill:#ffe6f0
style USE fill:#d4edda
style DOWNLOAD fill:#f8d7da
style RETURN fill:#d4edda
style EXEC fill:#cce5ff
```
## 五、Hash 校验机制
- 上传时计算 SHA256 并存入数据库
- Worker 使用前校验本地文件 hash
- 不匹配时自动重新下载
- 确保所有节点使用相同内容的字典
## 六、本地 Worker vs 远程 Worker
本地 Worker 和远程 Worker 获取字典的方式相同:
1. 从数据库查询字典元数据file_hash
2. 检查本地缓存是否存在且 hash 匹配
3. 不匹配则通过 HTTP API 下载
**注意**Worker 容器只挂载了 `results``logs` 目录,没有挂载 `wordlists` 目录,所以字典文件需要通过 API 下载。
```mermaid
sequenceDiagram
participant W as Worker (本地/远程)
participant DB as PostgreSQL
participant S as Server API
participant FS as 本地缓存
W->>DB: 1⃣ 查询数据库获取 file_hash
DB-->>W: 返回 file_hash
W->>FS: 2⃣ 检查本地缓存
alt 存在且 hash 匹配
FS-->>W: ✅ 直接使用
else 不存在或不匹配
W->>S: 3⃣ GET /api/wordlists/download/
S-->>W: 4⃣ 返回文件内容
W->>FS: 5⃣ 保存到本地缓存<br/>/opt/xingrin/wordlists/
FS-->>W: ✅ 使用缓存文件
end
Note over W,FS: 本地 Worker 优势:<br/>• 网络延迟更低(容器内网络)<br/>• 缓存可复用(同一宿主机多次任务)
```
### 本地 Worker 的优势
虽然获取方式相同,但本地 Worker 有以下优势:
- 网络延迟更低(容器内网络)
- 下载后的缓存可复用(同一宿主机上的多次任务)
## 七、配置项
`docker/.env` 或环境变量中配置:
```bash
# 字典文件存储目录
WORDLISTS_PATH=/opt/xingrin/wordlists
# Server 地址Worker 用于下载文件)
PUBLIC_HOST=your-server-ip # 远程 Worker 会通过 https://{PUBLIC_HOST}/api 访问
SERVER_PORT=8888 # 后端容器内部端口,仅 Docker 内网监听
```
## 八、常见问题
### Q: 字典文件更新后 Worker 没有使用新版本?
A: 更新字典内容后会重新计算 hashWorker 下次使用时会检测到 hash 不匹配并重新下载。
### Q: 远程 Worker 下载文件失败?
A: 检查:
1. `PUBLIC_HOST` 是否配置为 Server 的外网 IP 或域名
2. Nginx 8083 (HTTPS) 是否可达(远程 Worker 通过 nginx 访问后端)
3. Worker 到 Server 的网络是否通畅
### Q: 如何批量导入字典?
A: 目前只支持通过前端逐个上传,后续可能支持批量导入功能。