Skip to content

更细资产管理功能 - #377

Open
idacma-k wants to merge 9 commits into
AIPentest:mainfrom
idacma-k:feat/asset-auto-ingest-and-tree
Open

idacma-k wants to merge 9 commits into
AIPentest:mainfrom
idacma-k:feat/asset-auto-ingest-and-tree

Conversation

@idacma-k

Copy link
Copy Markdown

使通过大模型调用第三方工具运行的结果展示到资产管理界面。添加web页面截图功能。

背景:Agent 调用 subfinder/httpx/naabu/nmap 后,原始输出没有任何解析,
资产库收不到数据,资产页只能靠手工导入。

实现:
- internal/assetintel:4 个工具的解析器(httpx JSON/纯文本、nmap XML/文本、
  naabu、subfinder),统一清洗为结构化 Host(eTLD+1 域名、IP 校验、协议推断、
  指纹去重),纯函数、不依赖本项目其他包。
- internal/agent:新增 ToolResultHook,在工具成功返回后旁路回调;调用点已
  recover 隔离,任何异常不影响 Agent 主流程。
- internal/app/asset_ingest.go:把 Hook 接到数据库,按会话绑定的项目写入资产,
  Source 记为 tool:<name>,Tag 记 auto-collected。
- 新增 asset_fingerprints 表(asset_id/service/technology/version)。独立成表
  是为了避免改动 assets 的 20+ 处 SELECT/scan,降低回归风险;表结构在
  schemas/application.sql 声明,启动期 reconcileSchema 自动创建。
- GET /api/assets/tree:按 公司(项目) -> 域名 -> 子域名 -> IP -> 端口 -> 服务
  -> 指纹/版本 聚合。公司取资产绑定的项目名,未绑定归入「未绑定项目」。
- 前端新增「列表/层级」视图切换与七层树(折叠、搜索高亮、计数),复用既有
  apiFetch;仅新增文件与样式,未改动 assets.js / router.js。
- .gitignore:忽略 dev.yaml(含密钥)、data-dev/、log-dev/、reports/。

测试:
- assetintel 28 个表驱动用例;handler 树聚合 4 例;app 入库集成 3 例
  (httpx JSON、nmap XML 含 closed 端口过滤与版本、重复采集幂等)。
- 修复上游测试隔离问题:audit_time_test / project_time_test 原先直接打开仓库
  data/conversations.db(部署机上通常只读),改为先复制到临时目录再打开。
第二批接入 8 个工具(均按 tools/*.yaml 的实际参数与 stdout 形态实现):
- fscan / masscan / rustscan:端口、Web、漏洞混排输出
- amass:子域名枚举(纯文本 + -json 行)
- wafw00f:WAF 指纹(作为 Technology)
- katana / gau / waybackurls:URL 抓取结果,只保留 host/port/protocol

解析行为调整:
- URL 未显式端口时按 scheme 补默认端口(https→443、http→80、ftp→21),
  避免资产层级出现「端口 0」节点;httpx 同样生效。
- 解析不到任何主机时返回 (nil, nil),不再产生空资产。

修复(重要):资产去重键原先优先取 Domain(eTLD+1),当解析器填充 domain
后会令同一根域下的不同子域名算出同一个 dedup_key 而互相覆盖,
资产层级视图因此丢失「子域名」维度(a/b/c.example.com 只剩最后一个)。
改为 Host 优先(先把 URL / host:port 归一化成主机名再比较),其次 IP,最后 Domain。
这与既有并发测试的期望一致(Domain 为空、仅 Host 不同时应各自成条)。
目标环境资产数为 0,无需数据迁移;若其他环境已有资产数据,
升级后同目标可能重复出现一次,可按需手工清理。

前端:端口为 0(仅有域名、没有端口)时显示协议名或「未指定端口」并保留该节点,
避免上层节点出现「有计数、无子节点」的断层。

测试:assetintel 60 个用例(新增 8 个工具各 ≥2 样本 + 默认端口用例);
新增 TestUpsertAssetsKeepsSubdomainsSeparate;
入库集成新增 fscan(smb 服务指纹)与 katana(多子域/多端口)两例。
按 ARL 风格的资产视图重构资产页:顶部类型 tab
(子域名/站点/IP/服务/SSL证书/文件泄露/URL信息/全部资产/层级),
下方扁平表格 + 每个 tab 独立的筛选与分页;七层层级树降为其中一个 tab;
原「全部资产」列表(含导入/导出/批量操作)保持不变。

后端:
- 新增 asset_host_ips 表(host,ip,record_type,source,UNIQUE(host,ip,record_type))。
  assets 表一条记录只存一个 IP,且去重键是 host+port+protocol,
  同一子域名的多个 A 记录会被合并覆盖,无法展示「关联IP」多值,
  因此单独建表按 (host,ip,record_type) 累积,重复扫描天然幂等。
- 资产自动采集钩子同时写入域名解析关系(当前为 A 记录)。
- 新增 GET /api/assets/table?type=subdomain|site|ip|service
  &page=&page_size=&q=&source=&record_type=,
  返回 rows 与 facets(各 tab 计数);子域名行支持多值 IP,
  IP 行聚合关联域名数/端口数,服务行结合指纹表给出服务与版本。

前端:
- 新增 assets-table.js:9 个类型 tab、四类表格、每列筛选、分页、
  loading/空/失败重试三态、多值 IP 标签、来源 manual 显示为「手动导入」。
- SSL证书 / 文件泄露 / URL信息 三个 tab 当前为占位(对应采集尚未接入),
  不发请求并显示「未接入采集」说明。
- 「层级」复用既有七层树;「全部资产」用 CSS 显隐复用 assets.js 的完整列表。

测试:新增 7 个表格聚合/筛选/分面用例;database/handler/app/assetintel/agent 全包回归通过。
后续:三个占位 tab 需要新增采集能力(httpx -tls-grab、保留完整 URL、文件泄露数据源)。
站点截图由独立的本地 Node 服务(Playwright + Chromium)渲染:
主服务以 root 运行,不应该自己渲染不可信目标站点,因此把浏览器放进
非 root 的独立进程,主服务只做排队、落库与鉴权下发。

后端:
- 新增 internal/screenshot:有界队列 + 固定并发 worker,调用外部
  POST /shot 渲染,成功写入 data/screenshots/<assetID>.png 并落库;
  按 screenshot.min_interval_hours 对同一站点去重,强制重截可跳过。
- 新增 asset_screenshots 表(asset_id/status/file_path/status_code/
  title/error/width/height/captured_at):status 为 pending/running/
  done/failed,由 schemas/application.sql 声明、启动期 reconcileSchema 建表。
- 资产自动采集钩子在入库 http/https 站点后自动排队截图。
- 新增接口(用 query 参数而非 /assets/:id/screenshot,避免与
  /assets/tree、/assets/table 等静态路由在 Gin 路由树中冲突):
    GET  /api/assets/screenshot?id=         取 PNG(需登录)
    GET  /api/assets/screenshot/status?id=  查询状态
    POST /api/assets/screenshot?id=         手动重截
- /api/assets/table 的站点行附带 asset_id 与 screenshot 元信息。
- 配置 screenshot.*(默认开启;启动时探测 /health,不可用则降级为
  不自动截图,避免给每个资产写失败记录)。config.example.yaml 已补充说明。

安全:
- 浏览器以非 root 用户运行;systemd 单元带 NoNewPrivileges、
  PrivateTmp、ProtectSystem=full;
- 只接受 http/https,拒绝 file://、data: 等协议;渲染超时/并发/请求体
  均有上限;截图下发需要登录态,且落盘路径做目录穿越校验。

前端:
- 站点 tab 新增截图列(44px 缩略图,blob URL + 翻页/切 tab 释放),
  点击弹 lightbox 预览;覆盖 done/pending/running/failed/none/disabled 六态;
- 支持「重新截图」与 pending/running 自动轮询(2s×15 次),
  并新增「仅看无截图」筛选。

测试:screenshot 包 4 个用例(URL 构造/落盘/最小间隔/健康探测)、
app 自动排队集成测试、既有全包回归通过。
- asset-management(中英):新增「从 Agent 任务自动采集」与「站点截图」两节;
  补充资产视图(按类型分 tab 的表格 + 七层层级视图)、资产字段
  (解析关系多 IP、服务/指纹/版本)。
- 修正去重规则描述:实现已改为 Host(子域名级)优先、其次 IP、最后域名,
  原文写的「域名优先」既与实现不符,也会让人误以为子域名可被安全合并。
- configuration(中英):新增 screenshot.* 配置段、默认值、降级行为与落盘说明。
- deployment(中英):新增「站点渲染服务(可选)」安装步骤:
  Playwright + Chromium 以非 root 用户跑在独立 systemd 单元里,主服务只做
  排队与鉴权下发。
- README / README_CN:特性速览补充自动采集、资产视图、站点截图三条。

安装细节与安全事项见 docs/*/deployment.md 与 scripts/shot-service/README.md。
仓库只能复现代码,环境本身不在仓库里。本次把缺失的步骤固化:

- scripts/bootstrap.sh:一键完成依赖检查、编译、首次生成 config.yaml
  (不覆盖已有配置)、创建 data/log/tmp/screenshots 并处理权限、
  从模板安装并启用系统服务、以非 root 用户安装 Playwright。
  支持 --dry-run / --no-systemd / --skip-build / --run-user / --shot-user。
- scripts/systemd/cyberstrikeai.service.example:主服务单元模板
  (此前只存在于部署机,未入仓),占位符由 bootstrap 替换。
- deployment(中英):新增「从 GitHub 拉取后复现环境」一节,明确列出
  不在仓库中的项(分支、config.yaml、data/、二进制、Playwright 浏览器、
  systemd 单元、Go/gcc)及补齐方式,并给出 bootstrap 用法。

说明:本次只新增可复现性脚本与文档,不改动任何运行时行为。
- 修正克隆地址:Ed1s0nZ/CyberStrikeAI 已转移至 AIPentest 组织,
  安装指令里改用规范地址(旧地址虽会 301,但仓库迁移后重定向可能失效)。
- 「快速上手」新增「服务器 / systemd 部署」小节,说明 scripts/bootstrap.sh
  的用法与作用(含 --with-screenshot 安装站点截图服务)。
- 「配置」补充 screenshot.* 配置片段与安全边界提示(渲染服务非 root)。
- 「相关文档」新增资产管理指南入口;「项目结构」补充 scripts/ 目录
  (部署辅助与 systemd 单元模板)。
资产库新增「公司」tab:维护「公司 -> 主域名」归属,与项目解耦
(项目是一次任务的容器,公司是可跨项目的组织实体)。

后端:
- 新增 companies / company_domains 两张表。域名按 eTLD+1 归一化且全局唯一,
  状态为 confirmed / pending / ignored;company_id 为空表示「待归属」。
- 自动采集钩子把新出现的根域名登记为 pending;已确认/已忽略的域名不会被
  后续采集覆盖(避免打扰用户判断)。
- 新增接口:GET/POST /api/companies、PUT/DELETE /api/companies/:id、
  POST /api/companies/:id/domains、DELETE .../domains/:domainId、
  POST /api/companies/:id/lookup、GET /api/company-domains?status=pending、
  POST /api/company-domains/:id/confirm|ignore。
- RBAC:新路由登记到既有映射表,读写分别复用 asset:read / asset:write,
  否则会被中间件以「未配置访问权限」拒绝。
- 自动查找主域名:本地优先(匹配项目名/业务系统/部门统计根域名频次),
  配置 fofa.api_key 时再用 org 查询补充;纯 IP 不计为域名,同一行 host+domain
  只计一次;建议会标注已归属公司。
- 层级视图公司层改为三级判定:域名归属 -> 同名项目并入 -> 回退项目名,
  解决同名项目与公司各出一个节点的问题。

前端:
- 资产页新增「公司」tab(懒加载),含新增表单、公司卡片(域名/资产数/来源)、
  移除域名、编辑、删除(二次确认)、自动查找建议面板、待归属确认/忽略、
  pending 数量角标;空态/加载/失败重试齐全。
- 三份 i18n 各新增 43 个 assets.company.* key。

文档:资产文档中英各补「公司与主域名」一节(来源、待确认流程、自动查找、层级判定)。

测试:database 4 例(CRUD/归属唯一/删除回落 pending/自动登记不覆盖用户决定/
域名映射与资产计数/本地候选);company 4 例(URL 与 IP 提取、FOFA 聚合排序、
无 Key 警告、输入即域名);全包回归通过。
tab 顺序改为资产层级顺序:
公司 -> 主域名 -> 子域名 -> IP -> 端口 -> 站点 -> 指纹 -> SSL/文件泄露/URL -> 全部资产 -> 层级。

后端:
- 表格接口新增两种类型:
  - type=domain:来自 company_domains,含归属公司/状态/来源/资产数;
  - type=fingerprint:把逐资产指纹聚合成「技术/版本」维度的行,标出是否 web,
    供「指纹 -> 目录探测」判断。
- 行为聚合行(子域名/IP/端口/站点)新增 asset_ids 字段:子域名与 IP 行的
  asset_ids 可能对应多条资产,供前端批量排除与关联探测任务使用。
- 新增 DELETE /api/assets/fingerprints?technology=&service=&version=,
  用于「指纹」页的排除;拒绝空条件以避免误删全表。
- facets 增加 domain / fingerprint 计数。

前端(assets-table.js / index.html / i18n / style.css):
- 新 tab 与表格列(主域名:归属公司/状态/资产数/来源;指纹:技术/服务/版本/Web/资产数)。
- 每行操作:探测(主操作)+ 排除/恢复;每 tab 工具栏「添加」内联面板。
  子域名/IP/端口走 /api/assets/import,主域名走 /api/companies/:id/domains,
  指纹为派生数据不可手工添加。
- 逐层探测:确认后创建对话 -> 按 asset_ids 关联 scan-links -> 切到对话 ->
  填入该层提示词(含授权范围约束)并发送;非 Web 指纹按钮禁用。
- 排除/恢复走 PUT /api/assets/bulk(inactive/active),已排除行显示徽标;
  主域名走 ignore,指纹走 DELETE。
- 三份 i18n 各新增 52 个 key(type.tab/type.col/add/probe/exclude)。

文档:资产文档中英各补「层级化视图与逐层探测」一节(tab 顺序、三类操作、探测链路表、
授权范围提示)。

测试:新增指纹聚合(跨资产合并/is_web 判定/排序/空指纹跳过)与指纹删除
(精确删除、按服务删除、空条件拒绝);全包回归通过。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant