anggipradana/vacti

GitHub: anggipradana/vacti

一款端到端 TypeScript 实现的轻量级漏洞评估与威胁情报平台,集成主动扫描、被动 OSINT、威胁情报聚合与自动化报告生成。

Stars: 0 | Forks: 0

VACTI

vacti

三个服务(app、worker、Postgres)。没有 Redis,没有 Celery,没有 Ruby。端到端 TypeScript。 ## 目录 - [功能介绍](#what-it-does) - [技术栈](#stack) - [架构](#architecture) - [安装](#installation) - [教程:你的第一次扫描](#tutorial-your-first-scan) - [使用平台](#using-the-platform) - [API 参考](#api-reference) - [报告](#reports) - [配置](#configuration) - [测试和 QA](#testing-and-qa) - [Docker 和部署](#docker-and-deployment) - [项目结构](#project-layout) - [安全和范围](#security-and-scope) - [文档](#documentation) - [许可证](#license) ## 功能介绍 - **侦测 / VA**:一条直接的流水线,`subfinder (可选) -> httpx -> naabu -> nuclei`,外加针对检测到为 WordPress 的主机的条件性 **nuclei wordfence** 模板。全部使用 Go 工具。 每个漏洞都有 CVSS / CVE / 参考资料、AI 富化,以及一个漏洞分类状态工作流。 - **被动侦测和暴露 (Attack Surface)**:无需 key 的 OSINT 发现 - **VirusTotal**(被动 DNS:子域名、未检测到的 URL、IP 解析 / WAF 背后的源站)+ **Wayback Machine**(归档 URL)。发现的 URL 按文件类型分类(备份 / 配置文件 / 密钥 / db-dumps / …),并使用一个包含 23 条规则的 **暴露检测器** (AWS / GCP / GitHub / Slack / Stripe 密钥,JWT,私钥, DB URL,basic-auth,stealer/combo 凭据,…)。扫描 **模式**:`active`(二进制),`passive` (仅 OSINT,无指向目标的流量),`full`(passive -> feed -> active)。暴露发现反馈给 统一风险评分;凭据类命中结果交叉链接到泄露的凭据。 - **威胁情报**:OTX AlienVault + LeakCheck + 手动指标 + 行业安全新闻 (RSS,包括印度尼西亚语来源)+ 统一的 **风险评分**(带有被动 **暴露** 组件),在仪表板、TI 页面和报告中保持一致。 - **报告**:重新设计的 VA 和 TI 双语(EN/ID)PDF 报告(封面、目录、 环形图 + 条形图、子域名清单、漏洞摘要、漏洞卡片、审批表),使用 headless Chromium 渲染。支持按项目进行品牌化(logo、颜色、分类、签署人、 执行摘要)。 - **扫描**:启动 / 取消、**计划**(cron)、**子扫描**(部分重扫)、两次扫描的 **diff**、 实时 SSE 进度、完整的命令 + 活动审计。 - **平台**:多项目工作区、**RBAC**(SysAdmin / PenetrationTester / Auditor)在服务端强制执行、加密的 **API-key 保险库**(AES-256-GCM)、审计日志、全局搜索。 - **集成**:webhooks(Discord rich embed、Google Chat card、Slack、Telegram、通用型)、 针对高危漏洞和新泄露的自动警报、**AI** 富化 + 执行摘要 / 威胁叙述生成(Claude / OpenAI / DeepSeek / Kimi / Ollama),以及附带 OpenAPI 文档的一等公民类型化 REST API。 ## 技术栈 Next.js 15 (App Router) 和 React 19,Tailwind + shadcn/ui,tRPC + Hono + Zod,PostgreSQL + Drizzle ORM,**pg-boss**(存储在 Postgres 中的队列,无需 Redis),Vercel AI SDK,Playwright(e2e **以及** PDF 渲染),argon2id 密码哈希,一个 Nx monorepo,以及 Vitest。 ## 架构 ``` flowchart TD Browser["Browser (UI)"] --> Web["Next.js app: web UI + REST API (Hono)"] Client["External CLI / API client"] --> Web Web -->|"read / write"| PG[("PostgreSQL: data + pg-boss job queue")] Web -->|"enqueue scan / TI jobs"| PG Worker["worker (pg-boss consumer)"] -->|"poll jobs"| PG Worker -->|"active recon pipeline"| Tools["subfinder / httpx / naabu / nuclei (Go on PATH)"] Worker -->|"passive recon"| OSINT["VirusTotal / Wayback Machine (HTTP APIs)"] Worker -->|"threat intel"| TI["OTX / LeakCheck / RSS feeds"] Worker -->|"persist results"| PG ``` Web 应用提供 UI 和 REST API;worker 从队列消费任务并调用 shell 执行 Go 扫描器。参见 [`docs/explanation/architecture.md`](docs/explanation/architecture.md)。 ## 安装 ### 前置条件 | 要求 | 版本 | 备注 | | ----------- | -------------- | -------------------------------------------------------- | | Node.js | 22 或更新版本 | 整个技术栈基于 TypeScript | | PostgreSQL | 16 或更新版本 | 数据存储和任务队列 | | Go 扫描器 | 最新版 | 位于 `PATH` 中的 `subfinder`、`httpx`、`naabu`、`nuclei` | | Chromium | 通过 Playwright | PDF 渲染和 e2e;通过 `playwright install` 安装 | 四个 ProjectDiscovery 扫描器仅在真实扫描时需要(其余应用无需它们即可 运行)。使用 Go 安装它们: ``` go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest go install -v github.com/projectdiscovery/naabu/v2/cmd/naabu@latest # needs libpcap-dev go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest nuclei -update-templates # fetch templates once # 确保 $(go env GOPATH)/bin 在你的 PATH 上 ``` ### 设置项目 ``` # 1. Clone 并安装依赖 git clone vacti && cd vacti npm ci npx playwright install chromium # for PDF rendering + e2e # 2. 配置环境 cp .env.example .env # 生成加密密钥并将其粘贴到 .env 中: openssl rand -base64 32 # -> ENCRYPTION_KEY (32-byte base64) # 3. 创建数据库(示例 role vacti / vacti) createuser vacti --pwprompt # or use an existing role createdb vacti -O vacti # 在 .env 中设置 DATABASE_URL=postgres://vacti:vacti@localhost:5432/vacti # 4. 运行 migrations 并 seed 默认 scan profiles + keyword list npm run db:migrate npm run db:seed # 5. 启动 worker 和 app(两个终端) npx tsx apps/worker/src/main.ts # terminal 1: job worker npx next dev apps/web -p 3100 # terminal 2: web app + API ``` 打开 。没有单独的注册步骤:首次访问会显示一个 **“创建第一个管理员”** 表单,该账号将成为 SysAdmin。 ## 教程:你的第一次扫描 应用在 运行后的五分钟演练。 1. **创建管理员。** 首次加载时,填写邮箱和密码表单。你现在已作为 SysAdmin 登录。 2. **创建项目。** 转到 **Settings -> Projects**,输入名称(`Acme Corp`)和别名(`acme`), 然后点击 _Create project_。项目是界定后续所有内容范围的工作区,因此你可以 并排运行多个任务(如 rengginang)。 3. **添加目标。** 转到 **Targets**,在右上角的切换器中选择当前项目,输入 域名(`example.com`)。可选择性地粘贴预定义的子域名(这将跳过 subfinder)和自定义 请求头(由 httpx 和 nuclei 发送)。 4. **运行扫描。** 转到 **Vulnerability Assessment**,点击 _New scan_,选择目标和配置文件 (Quick / Standard / Deep),然后启动。详情页会实时流式传输逐阶段的进度, 并且你可以随时取消。 5. **分类漏洞。** 打开已完成的扫描。Vulnerabilities 标签页列出了带有严重性、 CVSS/CVE 的漏洞,并提供一键 _On Progress_ 审查切换以及完整的状态下拉菜单。使用状态 过滤器和 _Mark all reviewed_ 进行批量分类。点击漏洞上的 _AI_ 以获取富化后的 描述 / 影响 / 修复建议(需要 AI key)。 6. **生成报告。** 点击 _Generate report_ 以流式传输带有品牌标识的双语 PDF。 7. **威胁情报。** 转到 **Threat Intel**,选择项目,然后点击 _Refresh_ 以拉取 OTX 信誉、泄露的凭据和行业安全新闻。选择你的行业以过滤新闻, 分类泄露和头条新闻,然后生成 TI 报告。 ## 使用平台 | 区域 | 你可以做什么 | | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | **Vulnerability Assessment** | 启动(active / passive / full 模式)、取消、子扫描、对两次扫描进行 diff、以及 AI 富化的漏洞分类。 | | **Targets** | 添加域名、预定义子域名和针对每个目标的自定义请求头;侦测笔记。 | | **Attack Surface** | 被动 OSINT 结果:发现的 URL(文件类别过滤器)、暴露发现(掩码片段 + 分类)、IP 目录。 | | **Cyber Threat Intel** | OTX + LeakCheck + 受监控资产信誉(VT/OTX 判定)+ 行业/品牌新闻 + 被动暴露,所有这些共同计算出一个风险评分。 | | **Reports** | 针对 VA 和 TI 的品牌化 EN/ID PDF,包含签署人、分类和执行摘要。 | | **Settings** | 项目、计划扫描、扫描配置文件、API token、webhooks、AI 提供商 + key 保险库、用户/RBAC、审计日志。 | RBAC:**SysAdmin**(完全控制),**PenetrationTester**(运行扫描,修改漏洞), **Auditor**(只读)。在服务端的每一次变更中强制执行。 ## API 参考 每个 endpoint 都位于 `/api` 下,并且(除了三个公开的 endpoint 外)都需要 Bearer **API token**。 在 **Settings -> API tokens** 下创建 token。交互式文档位于 **`/api/docs`**(Redoc),原始规范位于 `/api/openapi.json`。 ``` export TOKEN=vct_xxx export BASE=http://localhost:3100/api auth=(-H "Authorization: Bearer $TOKEN") json=(-H 'content-type: application/json') ``` ### 公开(无 auth) | 方法 | 路径 | 目的 | | ------ | ------------------ | ------------------------------- | | GET | `/api/health` | 存活探针 | | GET | `/api/openapi.json`| OpenAPI 3 规范 | | GET | `/api/docs` | Redoc 交互式文档 | ### 已认证 | 方法 | 路径 | 目的 | | ------ | ---------------------------------- | ----------------------------------------------------------------------- | | GET | `/api/whoami` | 当前 token 的用户 | | GET | `/api/search?q=` | 跨资源的全局搜索 | | GET | `/api/targets` | 列出 targets | | POST | `/api/targets` | 创建 target(`projectId`、`domain`,...) | | GET | `/api/profiles` | 列出扫描配置文件 | | POST | `/api/profiles` | 创建扫描配置文件 | | POST | `/api/scans` | 启动扫描(`targetId`,可选的 `profileId`,`mode`:active/passive/full) | | GET | `/api/scans` | 列出扫描 | | GET | `/api/scans/:id` | 扫描详情 | | GET | `/api/scans/:id/results` | 子域名、endpoint、端口、漏洞 | | GET | `/api/surface/urls?projectId=` | 被动发现的 URL(可选的 `category`,分页) | | GET | `/api/surface/findings?projectId=` | 暴露发现(可选的 `type`) | | GET | `/api/surface/ips?projectId=` | Passive-DNS IP 解析 | | GET | `/api/scans/:id/events` | 实时进度 | | POST | `/api/scans/:id/cancel` | 请求取消 | | GET | `/api/scans/:id/diff?against=` | 将此扫描与较早的扫描进行 diff(`against` = 基准扫描 id) | | GET | `/api/schedules` | 列出计划扫描 | | POST | `/api/schedules` | 创建 cron 计划 | | DELETE | `/api/schedules/:id` | 删除计划 | | GET | `/api/threat-intel` | 项目的 TI 快照(风险,OTX,泄露) | | POST | `/api/threat-intel/refresh` | 将 TI 刷新任务加入队列 | | GET | `/api/indicators` | 列出手动指标 | | POST | `/api/indicators` | 添加手动指标 | | DELETE | `/api/indicators/:id` | 删除指标 | | POST | `/api/vulnerabilities/:id/status` | 设置漏洞的分类状态 | | POST | `/api/leaks/:id/status` | 设置泄露凭据的分类状态 | | POST | `/api/leaks/:id/toggle` | 切换泄露的已检查标记 | | GET | `/api/webhooks` | 列出 webhooks | | POST | `/api/webhooks` | 创建 webhook | | DELETE | `/api/webhooks/:id` | 删除 webhook | | POST | `/api/webhooks/:id/test` | 发送测试通知 | ### 示例:端到端扫描目标 ``` # 1. 在一个项目中创建 target curl -s "${auth[@]}" "${json[@]}" -XPOST "$BASE/targets" \ -d '{"projectId":"","domain":"example.com"}' # 2. 开始 scan(省略 profileId 以使用 worker 默认值) curl -s "${auth[@]}" "${json[@]}" -XPOST "$BASE/scans" \ -d '{"targetId":""}' # 3. 查看进度 (SSE) 或轮询结果 curl -s "${auth[@]}" "$BASE/scans//events" curl -s "${auth[@]}" "$BASE/scans//results" # 4. 与之前的 scan 进行 Diff curl -s "${auth[@]}" "$BASE/scans//diff?against=" ``` 错误使用标准代码:`401`(缺失/无效 token),`403`(RBAC 拒绝),`404`(未找到), `400`(验证错误,附带 Zod 问题列表)。 ## 报告 报告是流式传输 PDF 的 HTTP 路由(在浏览器中打开它们或使用 `curl -o`): ``` GET /reports/va/?type=full&lang=id # vulnerability assessment GET /reports/ti/?lang=en # threat intelligence ``` `type` 可以是 `full` 或 `summary`;`lang` 是 `en` 或 `id`。品牌化(logo、颜色、分类、 签署人、执行摘要)是在 Settings 下项目配置的。报告从不使用破折号, 并且布局遵循 BPRS-Hijra 参考设计。 ## 配置 | 变量 | 必需 | 用途 | | ------------------------------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------- | | `DATABASE_URL` | 是 | Postgres 连接字符串 | | `ENCRYPTION_KEY` | 是 | 32 字节 base64,AES-256-GCM 保险库 key | | `POSTGRES_PASSWORD` | docker | compose 技术栈的 Postgres 密码(设置一个强密码) | | `OTX_API_KEY`, `LEAKCHECK_API_KEY` | 否 | 威胁情报来源(如果未设置则优雅降级) | | `VT_API_KEY`, `URLSCAN_API_KEY` | 否 | 用于被动侦测的 VirusTotal + URLScan(Wayback 无需它们也可工作) | | `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `DEEPSEEK_API_KEY` / `KIMI_API_KEY` / `OLLAMA_BASE_URL` | 否 | AI 提供商(通过保险库覆盖按项目 / 系统默认的 key) | | `PROXY_URL` | 否 | 通过代理路由 worker 的出站 OSINT/deep-fetch 请求 | | `SCHEDULE_TZ` | 否 | 扫描计划和每日新闻的时区(默认为 `Asia/Jakarta`) | | `NEWS_RETENTION_DAYS` | 否 | 自动清理超过 N 天的威胁/品牌新闻(默认为 `90`) | 在加密保险库中设置的按项目 key(Settings -> Integrations)优先于这些 环境默认值。 ### 使用自定义 / 兼容 endpoint 进行 AI 富化 默认情况下,Anthropic 和 OpenAI 会与其官方云 API 通信。你可以将它们指向任何 **兼容 OpenAI 或 Anthropic 的** endpoint —— 本地代理、内部网关、 [LiteLLM](https://github.com/BerriAI/litellm),或 [claude-code-router](https://github.com/musistudio/claude-code-router) —— 而无需更改你其余的设置。 1. 打开 **Settings -> Integrations -> AI enrichment**。 2. 选择 **Provider**(Anthropic 或 OpenAI)以及你的 endpoint 期望的 **Model** 名称。 3. 将 **Base URL** 设置为你的 endpoint,例如 `http://localhost:4000/v1`(LiteLLM)或你的网关的 基础路径。保持 **空白** 以使用官方云 API。 4. 将你的 endpoint 期望的 API key 放入该提供商的 **加密保险库**(同一页面)中 —— 或放入 `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` 中。Base URL 仅更改请求发送到 _哪里_; key 字段保持不变。 5. 保存,然后点击任意漏洞上的 **AI** 以验证针对你的 endpoint 的富化是否有效。 注意: - Base URL 是 **按项目** 划分且可选的;它绝不会影响其他项目或你的 API key。 - 它必须是完整的 `http(s)://` URL(无效值将被忽略并回退到云端默认值)。 - 对于 **完全本地** 的模型,请改用通过 `OLLAMA_BASE_URL` (默认为 `http://localhost:11434`)配置的 **Ollama** 提供商。 - 这允许你通过由你自己的 Claude 凭据支持的网关路由富化,因此你 并不局限于单独的按量付费 API key。 ## 测试和 QA 三个层级加上端到端(参见 [`docs/how-to/run-tests.md`](docs/how-to/run-tests.md)): ``` npm run test:quick # unit (Vitest) npm run test:integration # integration (needs Postgres) npm run e2e # Playwright e2e (headless) npm run e2e:ui # Playwright UI mode (interactive, headed/desktop) ``` CI 在质量门禁后运行类型检查 + lint + 所有三个层级。 ## Docker 和部署 ``` make up # app + worker + Postgres (migrations auto-run) make down # stop the stack ``` 设计为位于 **Cloudflare Tunnel** 之后(无入站端口)。参见 [`docs/how-to/deploy.md`](docs/how-to/deploy.md) 和 [`docs/planning/03-API-AND-DEPLOY.md`](docs/planning/03-API-AND-DEPLOY.md)。 ## 项目结构 ``` apps/ web (Next.js), worker (pg-boss) libs/ @vacti/{core,config,db,auth,queue,ui,recon,threat-intel,reports,api,integrations} .claude/ ccpm planning: prds/ and epics//{epic.md, 00N.md} repo-governance/ six-layer governance (vision to workflows) docs/ Diataxis docs (tutorials/how-to/reference/explanation) + planning decision records drizzle/ SQL migrations (0000+) ``` ## 安全和范围 仅扫描 **已授权** 的目标。Secret 仅存在于 `.env` 或加密保险库中,绝不会 被记录或提交。RBAC 在服务端的每一次变更中强制执行。参见 [`SECURITY.md`](SECURITY.md)。 v1 版本暂不支持:bug-bounty 同步、截图、重度 OSINT、多组织、代理。 ## 文档 - 教程和操作指南:[`docs/`](docs/) - 规划和决策:[`docs/planning/`](docs/planning/) - 治理和约定:[`repo-governance/`](repo-governance/) - 贡献:[`CONTRIBUTING.md`](CONTRIBUTING.md) ## 许可证 基于 **GNU General Public License v3.0** 授权。你可以根据 GPL 的条款使用、学习、分享和修改它;衍生作品必须保持 GPL 许可。有关全文,请参见 [`LICENSE`](LICENSE)。 这与 vacti 重写的 reNgine 血统保持一致。
标签:CISA项目, GitHub, StruQ, TypeScript, 威胁情报, 安全插件, 安全测试, 实时处理, 开发者工具, 攻击性安全, 测试用例, 特征检测, 网络测绘, 自动化攻击