# IDC 可疑域名审计平台 **Repository Path**: stoploss/idc-domain-audit ## Basic Information - **Project Name**: IDC 可疑域名审计平台 - **Description**: 从 Zeek 网络日志发现 IDC 可疑域名并生成可复核的 HTTP/浏览器扫描证据与风险评分。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: https://gitee.com/csbsgyl/idc-domain-audit - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-09-08 - **Last Updated**: 2026-09-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # IDC 可疑域名审计平台 从 Zeek 网络日志发现落在指定 IDC 网段的域名,自动还原 HTTP 与浏览器跳转链,结合备案、白名单和行为特征进行风险评分,并保存可复核的扫描证据。 > 本系统输出的是安全审计风险,不是对域名或网站违法性质的法律认定。 ## 数据流 ```text Zeek JSON 日志 -> 域名采集 -> PostgreSQL -> BullMQ |-> HTTP/HTTPS 扫描 |-> Playwright 浏览器扫描 `-> 风险评分、证据和管理后台 ``` 采集器读取 `http.log`、`ssl.log` 和 `dns.log`,只接受响应 IP 或 DNS Answer 落入启用 IDC 网段的记录。新域名立即扫描,调度器随后每 24 小时复查。风险结果分为 `LOW`、`MEDIUM`、`HIGH`、`CRITICAL`。 ## 快速启动 要求:Linux 服务器使用 `root` 或具有无密码 `sudo` 权限的云主机默认账号执行。Git、Docker Engine 或 Compose v2 缺失时,一键脚本会自动安装、启动 Docker 并设置开机自启;已有完整 Docker 环境不会重复安装。 ### 一键部署(推荐) 部署主机只需要执行一条命令。它会补齐 Git 和 Docker、拉取 Gitee 仓库、创建 `.env.production`、自动生成高熵 PostgreSQL 密码和 API 令牌、设置文件权限为 `600`、构建并启动完整 Compose 栈,最后检查数据库迁移、Zeek 日志挂载、浏览器沙箱、API 就绪、前端页面和前端 API 代理: ```bash curl -fsSL https://gitee.com/csbsgyl/idc-domain-audit/raw/main/deploy.sh | bash ``` 需要手动保留 checkout 流程时,也可使用下面这条等价命令: ```bash git clone --depth 1 https://gitee.com/csbsgyl/idc-domain-audit.git && cd idc-domain-audit && ./deploy.sh ``` 流式入口默认把代码放在当前目录的 `idc-domain-audit/`;可用 `DEPLOY_DIR=/opt/idc-domain-audit` 指定目录,用 `DEPLOY_REPOSITORY_URL` 和 `DEPLOY_BRANCH` 指定仓库或分支。已有 checkout 只有在远端、分支均匹配且不含本地或未跟踪改动时才会快进更新;不会执行普通目录中的同名脚本。可设置 `AUTO_INSTALL_GIT=0` 禁用 Git 自动安装。 国内服务器默认使用阿里云 Docker CE 软件源、DaoCloud/1ms Docker Hub 镜像加速和 npmmirror 包源。Playwright 大镜像会先用 1 MiB 实际层下载探测微软 MCR 直连,最长等待 12 秒;直连不可用时自动回退 DaoCloud。重复部署会把旧版 DaoCloud 默认值迁移到本次探测出的较优来源,显式设置的 `PLAYWRIGHT_IMAGE` 不会被覆盖。PostgreSQL、Redis 继续通过 DaoCloud 拉取;三类镜像均固定为已核对的官方 digest。Docker 安装器不可用时,脚本会按发行版直接配置国内 Docker CE 仓库,并将 Rocky/AlmaLinux 映射到 CentOS 镜像路径、将常见 Alibaba Cloud Linux 版本映射到兼容仓库。即使服务器已安装 Docker 但未配置 Hub 加速,默认镜像也不直连 Docker Hub。只在全新 Docker 安装且 `/etc/docker/daemon.json` 不存在时写入镜像加速配置;已有 daemon 配置会原样保留。可通过 `DOCKER_DOWNLOAD_URL`、`DOCKER_REGISTRY_MIRRORS`、`PLAYWRIGHT_IMAGE`、`POSTGRES_IMAGE`、`REDIS_IMAGE` 和 `NPM_REGISTRY` 覆盖,或设置 `AUTO_INSTALL_DOCKER=0`、`CONFIGURE_DOCKER_MIRRORS=0` 禁用对应自动操作。 脚本默认将管理端口绑定到 `127.0.0.1:8048`,API 绑定到 `127.0.0.1:8047`。远程访问应通过 HTTPS 反向代理和统一身份认证,不要直接把端口改为公网监听。IDC 网段是业务事实,不会被随机生成;运行前可按实际网络覆盖: ```bash IDC_NETWORKS=110.42.102.0/24,110.42.66.0/24,110.42.58.0/24 ./deploy.sh ``` 首次部署生成的密码和令牌只写入目标机的 `.env.production`,不会提交到 Git,也不会默认打印。重复运行会复用已有有效凭据;如果发现同名 PostgreSQL 数据卷但环境文件丢失、数据库身份不一致或仍是默认密码,脚本会停止并要求先恢复原配置,不会盲目轮换数据库凭据。只生成并检查配置、不启动 Compose 时可使用 `./deploy.sh --prepare-only`;如果 Docker 不可用且这是明确确认过的新机器,可加 `--assume-new-install`,否则脚本会拒绝在无法确认数据库卷状态时生成或轮换数据库凭据。查看帮助使用 `./deploy.sh --help`。 ```bash ./deploy.sh --prepare-only --assume-new-install ``` `--prepare-only` 会先检查网段、CORS 来源、绑定地址、端口和数据库 URL 的基础格式,但不会替代应用启动后的完整配置校验。 脚本会把完整配置先写入同目录临时文件,全部校验通过后再原子替换正式环境文件;因此参数错误不会留下半成品配置。环境文件必须是 `.env` 或 `.env.*` 文件,不能指向 `.env.example` 或符号链接。 部署完成后,环境文件位置和访问地址会显示在终端;受保护 API 的令牌可从该环境文件读取。生产环境强制使用 `ICP_PROVIDER=manual`,备案数据仍需通过可信数据源或人工复核写入。 默认 Zeek 目录是 `data/zeek/current/`。一键部署会创建空目录并验证容器可读;目录为空时服务仍会启动,但不会产生新的日志观测。接入真实 Zeek 输出时,将 `ZEEK_LOG_HOST_DIR` 指向宿主机实际日志目录,并确保容器用户具备目录和日志文件的读取权限。 ### 手动 Compose 入口(可选) 只有需要完全自定义 Compose 参数时才使用手动入口;普通部署不需要执行下面这组命令: ```bash cp .env.example .env # 至少修改 POSTGRES_PASSWORD、DATABASE_URL、API_AUTH_TOKEN、IDC_NETWORKS, # 并将 ICP_PROVIDER 改为 manual;生产配置不满足这些条件会拒绝启动。 chmod 600 .env ./scripts/compose.sh up --detach --build --wait ``` 使用其他环境文件时,通过项目包装脚本显式指定,所有 Compose 插值和容器运行参数都会从同一文件解析: ```bash APP_ENV_FILE=.env.production ./scripts/compose.sh up --detach --build --wait ``` `APP_ENV_FILE` 是本项目脚本的约定,不是 Docker Compose 原生变量。不要写成 `APP_ENV_FILE=.env.production docker compose up`,因为原生命令不会因此自动采用该文件,可能继续从默认 `.env` 插值。所有生产运维命令都应使用 `./scripts/compose.sh`、`backup.sh`、`restore.sh` 或 `retention.sh`;相对环境文件路径按项目根目录解析。烟测使用独立的 `SMOKE_ENV_FILE` 参数,不能与生产脚本混用。 启动后访问: - 管理后台: - API 存活检查: - API 就绪检查:(配置 `API_AUTH_TOKEN` 时需带 Bearer 令牌) 查看状态和日志,或停止服务: ```bash APP_ENV_FILE=.env.production ./scripts/compose.sh ps APP_ENV_FILE=.env.production ./scripts/compose.sh logs --tail=200 APP_ENV_FILE=.env.production ./scripts/compose.sh down ``` 生产部署前必须设置至少 16 位数据库密码、同步更新 `DATABASE_URL`、生成至少 32 位高熵 `API_AUTH_TOKEN`、确认 IDC 网段并使用 `ICP_PROVIDER=manual`。任一条件不满足时,生产进程会拒绝启动。管理端口默认只发布到宿主机回环地址;需要远程访问时,应通过 HTTPS 反向代理和统一身份认证网关转发前端,而不是直接暴露 API 端口。Zeek 应输出逐行 JSON;默认读取 `data/zeek/current/`,也可通过 `ZEEK_LOG_HOST_DIR` 挂载宿主机上的实际日志目录。 以下配置需要一起调整: - 修改 `API_PORT`、`WEB_PORT` 或 `WEB_BIND_PORT` 后,同步修改 `CORS_ORIGINS` 中的前端来源。 - 设置高熵 `API_AUTH_TOKEN` 后,前端代理会在服务端自动附加令牌;`/api/health` 是免认证 liveness,`/api/ready` 是检查数据库、Redis 和队列的鉴权 readiness。 - `DATABASE_URL` 在 Compose 中应使用主机名 `postgres`,本地直接运行时改为 `localhost`。 - `DATABASE_POOL_MAX` 默认每进程 10 个连接;应按 PostgreSQL 总连接预算和实际服务副本数调整。 - `API_RATE_LIMIT_MAX` 和 `API_RATE_LIMIT_WINDOW_MS` 控制单个 API 实例按来源 IP 的全局限流。若通过反向代理部署,需要在受信任网关层继续执行用户级限流。 - HTTP 阶段会把下一次调度暂缓 `SCAN_RETRY_DELAY_MS`,浏览器阶段结束后才确认 24 小时周期;调度器会把超过 `SCAN_RUN_STALE_AFTER_MS` 的遗留在途记录标记为超时。 - 自定义环境文件必须通过 `APP_ENV_FILE=<文件> ./scripts/compose.sh ...` 指定;包装脚本会传给 Compose 的 `--env-file`。不要只设置一个额外的 `env_file` 变量,以免插值参数来自不同配置源。 - 扫描证据保存在 Compose 命名卷 `evidence-data`,通过后台证据接口读取。 - Compose 会先等待 PostgreSQL 健康并完成全部迁移,再启动业务服务;业务服务还会等待 Redis 健康,前端则等待 API 的数据库、Redis 和队列检查全部通过。 - 应用容器默认丢弃 Linux capabilities,并限制 Docker 日志文件大小;前端容器不会获得数据库或 Redis 凭据,也不接入后台数据网络。`backend` 网络标记为 Docker internal,PostgreSQL、Redis 和普通后台服务不能直接出网;HTTP 与浏览器扫描器额外接入受控的 `egress` 网络以访问待审计站点。API、前端、PostgreSQL、Redis 和四个后台进程均配置了容器健康检查,`./scripts/compose.sh up --wait` 会等待整套服务就绪。 - 采集器、调度器和两个扫描 Worker 的 `API_AUTH_TOKEN` 被显式清空;它们仍需要数据库和 Redis 连接,因此正式生产环境还应为 PostgreSQL/Redis 配置独立的最小权限账号和 ACL。当前 Compose 默认账号是部署便利配置,不应直接作为跨租户生产隔离方案。 - HTTP 健康探针使用镜像内 Node 的 `fetch`,后台进程使用数据库心跳探针(最近 45 秒且状态为 `RUNNING`);不依赖宿主机的 `curl`、`grep` 或其他临时工具。 - 迁移脚本会记录每个 SQL 文件的 SHA-256;已应用迁移文件被改写时,后续启动会失败并要求人工处理,不会静默继续。 ### 备份、恢复与数据保留 运维脚本默认是只读演练模式,且都要求真实环境文件(拒绝 `.env.example`)。先确认目标项目和环境文件,再执行: ```bash APP_ENV_FILE=.env.production ./scripts/backup.sh --dry-run APP_ENV_FILE=.env.production ./scripts/backup.sh --apply ``` 备份目录包含 PostgreSQL custom-format dump、证据卷 `evidence.tar.gz`、Redis RDB 快照、元数据和 `SHA256SUMS`。实际备份会优雅停止前端、API、采集器、调度器和两个扫描器,确保数据库记录与证据文件不在写入中;PostgreSQL 和 Redis 保持运行。脚本会检查 `PGDMP`/`REDIS` 文件签名、归档路径和校验和,并在完成后恢复原先运行的服务。备份目录含敏感审计数据,应限制为 `0700` 并复制到加密的异地主机或对象存储;不要把它提交到 Git。 恢复先做完整校验,不会改动服务: ```bash APP_ENV_FILE=.env.production ./scripts/restore.sh --dry-run backups/site-audit-20260729T120000Z ``` 确认备份属于同一个数据库名、目标 Compose 项目和预期时间窗口后,才允许替换数据: ```bash APP_ENV_FILE=.env.production ./scripts/restore.sh \ --apply --confirm-restore backups/site-audit-20260729T120000Z ``` 恢复是明确的替换操作:数据库使用单事务 `pg_restore`,证据卷和 Redis 队列随后替换。若在替换开始后失败,脚本会让应用服务保持停止以便人工核对,不会假装恢复成功;修复原因或切换到另一份已校验备份后再重试。恢复后应检查 `./scripts/compose.sh ps`、`/api/health`、带令牌的 `/api/ready`、后台心跳和最近一条扫描。 扫描历史默认保留 90 天,并且每个观测域名至少保留最近 5 次扫描。先查看预计删除量: ```bash APP_ENV_FILE=.env.production RETENTION_DAYS=90 RETENTION_KEEP_LATEST=5 \ ./scripts/retention.sh --dry-run ``` 确认工单后执行删除(必须同时给出确认参数): ```bash APP_ENV_FILE=.env.production RETENTION_DAYS=90 RETENTION_KEEP_LATEST=5 \ ./scripts/retention.sh --apply --confirm-delete ``` 保留脚本会暂停会写扫描数据的应用服务,先删除数据库中的 `scan_runs`(相关导航事件和证据索引按外键级联),再按已删除的 UUID 清理证据目录,最后恢复原先运行的服务。它不会删除观测域名、备案记录或白名单;删除失败时会保留 UUID 清单供人工对账。建议至少每周执行一次 dry-run,并在异地备份验证通过后再执行 apply。 ### Zeek 日志轮转 采集器按 `(域名, IP, 端口)` 保存扫描端点,同一域名同时出现 80 和 443 时会分别维护扫描状态。文件游标采用至少一次语义:数据库、Redis 或 offset 保存失败时不会跳过日志,极端恢复场景可能重放已处理记录,但不会把重放当成新的端点。 活跃日志正常追加时,采集器会验证文件头、旧 EOF 边界和本次读取字节后继续推进,不会仅因 size/mtime 变化就从零回放;检测到 `copytruncate`、前缀改写或读取期间内容变化时,则丢弃未确认字节并从安全边界重试。 轮转恢复会递归查找当前日志目录中的以下未压缩文件名(`ssl`、`dns` 同理): - `http.log.*` - `http.*` - `http-*` - 轮转子目录中的 `http.log` 采集器不直接读取 `.gz`、`.bz2`、`.xz` 或 `.zst` 归档。logrotate 应启用 `delaycompress`,并保证轮转文件在采集器完成 checkpoint 前不被压缩或删除。`ZEEK_DEDUP_WINDOW_MS` 控制进程内事件去重窗口,`ZEEK_DEDUP_MAX_ENTRIES` 是去重表硬上限;高流量环境应结合事件速率和容器内存调整。 宿主机目录和日志文件必须允许镜像内的非 root 用户 `pwuser` 遍历并读取。Linux 上可先用 `APP_ENV_FILE=.env.production ./scripts/compose.sh run --rm --no-deps collector id` 查看容器 UID/GID,再通过 ACL 或日志组授权;若启用了 SELinux,还需在 collector 的 bind mount 上使用合适的 `:z`/`:Z` 标签。不要为了省事把日志设为全局可写。 ### Compose 烟测 一键构建隔离栈并验证迁移、多端口端点约束、API、前端代理、容器状态、所有服务心跳,以及启用沙箱的 Chromium 启动和渲染: ```bash pnpm smoke:compose # 或直接运行 ./scripts/smoke-compose.sh ``` 脚本优先读取 `.env`,不存在时使用 `.env.example`;它使用独立的 Compose project、数据库卷、容器内 PostgreSQL/Redis、动态高位回环端口和非空测试令牌,不会连接环境文件中配置的外部数据库或 Redis。结束后只删除本次创建的容器和卷。任何检查失败都会先输出容器状态和最近日志。常用参数: ```bash SMOKE_TIMEOUT_SECONDS=300 ./scripts/smoke-compose.sh SMOKE_ENV_FILE=.env.production ./scripts/smoke-compose.sh SMOKE_API_HOST_PORT=18047 SMOKE_WEB_HOST_PORT=18048 ./scripts/smoke-compose.sh SMOKE_API_AUTH_TOKEN=another-test-token ./scripts/smoke-compose.sh SMOKE_KEEP=1 ./scripts/smoke-compose.sh # 保留失败现场供排查 ``` 导入仓库内的 Zeek 示例: ```bash ./scripts/compose.sh run --rm -e ZEEK_LOG_DIR=/app/fixtures/zeek -e ZEEK_IMPORT_ONCE=true collector ``` 可选测试站点: ```bash ./scripts/compose.sh --profile demo up test-site ``` ## 本地开发 要求 Node.js 22.22+、pnpm 10、PostgreSQL、Redis、curl,以及 Playwright Chromium。 ```bash pnpm install cp .env.example .env # 将 DATABASE_URL 和 REDIS_URL 中的主机名改为 localhost pnpm migrate pnpm exec playwright install chromium pnpm dev ``` 采集器需单独启动: ```bash pnpm start:collector ``` 常用检查: ```bash pnpm typecheck pnpm lint pnpm test pnpm build:frontend pnpm smoke:compose ``` ## 风险规则 主要规则包括跨可注册主域跳转、目标不在白名单、ICP 未查询到、JavaScript/Meta Refresh 跳转、外部自动弹窗、未备案 iframe、SSRF 目标拦截、历史目标变化、DNS 与观测 IP 不一致、IP 直连和异常端口。规则和权重位于 `packages/scanner-core/src/index.ts`。 ### ICP 数据源 `ICP_PROVIDER=mock` 只用于演示和测试:`ICP_MOCK_FILED_DOMAINS` 中列出的可注册主域返回“已备案”,其余返回“未查询到”,结果缓存 24 小时。它不是真实备案查询,生产环境必须切换为 `ICP_PROVIDER=manual`,再由可信数据源或人工复核写入记录: ```bash curl -X PUT http://127.0.0.1:8047/api/domains//icp \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ -d '{"status":"FILED","icpNumber":"京ICP备XXXXXXXX号","entityName":"示例主体"}' ``` 可用状态为 `FILED`、`NOT_FOUND`、`UNKNOWN`、`QUERY_FAILED`、`MANUAL_REVIEW` 和 `WHITELISTED`。仅本地开发模式允许不配置 `API_AUTH_TOKEN`;生产模式缺少高熵令牌会拒绝启动。 ## 安全边界 - 首跳仅允许使用启用 IDC 网段中的观测 IP。 - 后续 URL 仅允许 HTTP/HTTPS,禁止认证信息、localhost、私网和保留地址。 - HTTP 扫描使用 `curl --resolve` 固定每一跳解析结果,降低 DNS Rebinding 风险。 - 浏览器扫描在每次请求前校验目标,并通过本地固定地址 SOCKS 代理连接同一个已验证 IP,避免校验后由 Chromium 二次解析造成 DNS Rebinding。 - 浏览器 Worker 以非 root 用户运行,开启 Chromium 沙箱,并使用 Playwright 官方 seccomp 策略。 - 证据文件限制名称、大小和目录范围,下载前重新校验 SHA-256;HTML、JSON 和文本证据强制作为附件下载,只有 PNG 截图允许内联查看。 - API 使用来源白名单、生产强制 Bearer Token、安全响应头和限流,但没有用户、角色和登录审计体系。前端代理会代发共享服务令牌,因此能访问前端即等同管理员权限;正式对外提供管理后台前必须接入统一身份认证网关,并在网关记录用户身份和操作日志。