kayefi737/AegisScan

GitHub: kayefi737/AegisScan

一款基于 FastAPI 的网站外部安全态势被动扫描器,能在十秒内完成九大类 20 余项只读检查并给出透明评级和具体修复方案。

Stars: 0 | Forks: 0

# 🛡️ AegisScan **在大约十秒钟内评估任何网站的外部安全态势。** 你只需输入一个主机名。AegisScan 会跨越 **九个**类别运行 20 多项被动的、只读的检查,计算出一个透明清晰的 **A+ → F** 评级,并返回一份报告,其中每一个失败项都附带用于修复的*确切配置行*及其 *OWASP Top-10* 映射。无需安装、无需注册、运行它也不需要任何外部服务。 AegisScan 是 **PostureScan**(TechCrush 云计算第 6 期,第 12 组)的强化版本。它保留了 PostureScan 的所有优点(即时评级、具体修复方案、访客扫描、注重隐私的公共仪表板),并将 PostureScan 自己的“未来工作”幻灯片中的几项内容直接推向了产品级:更深度的检查、OWASP 映射,以及一流且有完善文档的 REST API。它还可以通过**单条命令运行,且完全不依赖任何托管服务**,这是原版做不到的。 ## 目录 1. [核心想法](#-the-idea) 2. [相较于 PostureScan 的强化之处](#-whats-stronger-than-posturescan) 3. [工作原理(流程)](#-how-it-works-the-flow) 4. [架构](#-architecture) 5. [技术栈](#-tech-stack) 6. [检查项(全部九大类别)](#-the-checks-all-nine-categories) 7. [评分标准](#-scoring-rubric) 8. [快速开始](#-quick-start) 9. [配置](#-configuration) 10. [REST API 参考](#-rest-api-reference) 11. [报告](#-reports) 12. [安全模型与 SSRF 防护](#-security-model--the-ssrf-guard) 13. [测试](#-testing) 14. [项目结构](#-project-structure) 15. [部署与 CI/CD](#-deployment--cicd) 16. [路线图](#-roadmap) 17. [负责任地使用](#-responsible-use) 18. [许可证](#-license) ## 💡 核心想法 关于当今的 Web 安全,有三件事是事实: 1. **几乎每个生产环境网站都至少有一个极其容易修复的配置错误**:缺少安全标头、Cookie 没有设置 `Secure`、域名没有 DMARC 记录。 2. **要找出这些问题通常意味着你需要组装五种专业工具**,并阅读五种不同的规范。 3. **综合扫描器都隐藏在注册门槛和定价页面之后**,而免费工具各自只覆盖一个类别。 所以,尽管每个人都同意应该运行这些检查,但实际上几乎没有人去运行。AegisScan 弥补了这一差距:**一个输入,一份报告,每一项检查,都为你写好了修复方案。** ## 🚀 相较于 PostureScan 的强化之处 | 领域 | PostureScan | **AegisScan** | |---|---|---| | 检查类别 | 8 | **9**(增加了专门的深度 CSP 类别 + `.well-known`) | | 邮件认证 | DMARC | **SPF + DMARC + CAA + DNSSEC** | | 标头覆盖范围 | 核心集合 | 增加了 **Referrer-Policy, Permissions-Policy, COOP, version-disclosure** | | OWASP 映射 | 未来工作 | **每一项发现都映射到 OWASP Top-10 2021** ✅ | | 文档化的 REST API | 未来工作 | **在 `/docs` 自动生成 OpenAPI/Swagger** ✅ | | 扫描引擎 | 顺序执行 | **异步、并发探测**(`asyncio.gather`) | | 评分机制 | 显示评级 | **公开、可复现的加权评分标准**(`/api/meta`) | | 运行环境要求 | React + Django + Supabase + Railway + Vercel | **一条 `uvicorn` 命令,SQLite,零托管服务** | | 报告 | PDF(需认证) | **JSON + HTML(公开)+ PDF(需认证)** | | 驱动/运行时 bug | 在 Py 3.13 上遇到 `psycopg2` + Sentry 崩溃 | **内置 `psycopg` v3 + Sentry ≥ 2.61**,预先修复了那些确切的 bug | | 增加检查项 | 编辑扫描器 | **在检查模块中丢入一个函数**,运行器会自动识别 | 最后三行是刻意为之的:PostureScan 自己的幻灯片 9-10 记录了 `psycopg2`-on-Python-3.13 故障、Sentry 递归崩溃以及 CORS 预览不匹配的问题。AegisScan 锁定了已修复的版本,并使用一条 CORS 正则表达式规则,从而确保这些问题永远不会在此发生。 ## 🔄 工作原理(流程) ``` hostname ─▶ normalize ─▶ SSRF guard ─▶ probe (concurrent) ─▶ evaluate ─▶ score ─▶ store ─▶ report │ │ │ │ │ │ │ └─ weighted A+→F grade │ │ └─ 20+ pure check functions read the probe │ └─ HTTPS GET, HTTP GET, TLS handshake, DNS, /.well-known (in parallel) └─ resolve + reject private / loopback / reserved IPs ``` 1. **标准化** 输入:剥离协议、路径、端口、用户信息 → 纯主机名。 2. **防护**:解析它,如果它指向私有、环回、链路本地或保留地址,则拒绝继续(SSRF 防护)。 3. **并发探测一次**:一个 HTTPS 请求(跟随重定向)、一个普通 HTTP 请求(测试重定向到 HTTPS)、一个原始 TLS 握手、一批 DNS 查询,以及一个 `/.well-known/security.txt` 抓取,所有这一切同时并行进行。 4. **评估**:每一项检查都是一个*纯函数*,它读取共享的探测数据并返回结果。没有任何检查会发起自己的网络调用,因此引擎运行极快且在测试中具有确定性。 5. **评分** 根据公开的评分标准 → 评级。 6. **存储** 完整的结构化结果并将其返回。 ## 🏗️ 架构 ``` ┌──────────────────────────────────────────────┐ Browser ───▶ │ FastAPI app (uvicorn) │ (SPA) │ ├─ / served single-page frontend │ │ ├─ /api/* JSON REST API + JWT auth │ │ ├─ /docs auto OpenAPI / Swagger UI │ │ └─ scan engine async, pure check functions │ └───────────────┬──────────────────────────────┘ │ SQLAlchemy ▼ ┌────────────────────────┐ │ SQLite (default) │ swap to Postgres │ or Postgres (optional) │ with one env var └────────────────────────┘ The scan engine reaches OUT to target sites, strictly read-only, behind an SSRF guard that blocks private address space. ``` 与 PostureScan 的五服务生产拓扑(React/Vercel ×2 + Django/Railway ×2 + Supabase)不同,AegisScan 是 **单进程** 运行的,同时提供 API 和前端服务。这是一个经过深思熟虑的权衡:对于单团队项目来说,运行和推理都变得极其简单;而且由于除了数据库之外它是无状态的,它仍然可以在负载均衡器后进行横向扩展。 ## 🧰 技术栈 | 层级 | 选择 | 原因 | |---|---|---| | API | **FastAPI**(Python 3.11–3.13) | 异步、强类型、免费的 OpenAPI 文档 | | 服务器 | **uvicorn** | ASGI,一条命令搞定 | | ORM / DB | **SQLAlchemy 2** → 默认 **SQLite** / 可选 **Postgres** | 本地零配置,需要时即可投入生产 | | 认证 | **JWT**(python-jose)+ **bcrypt**(passlib) | 无状态的访客 + 认证流程 | | 探测 | **httpx**(异步)+ 标准库 `ssl`/`socket` + **dnspython** | 高并发,无重依赖 | | 报告 | **Jinja2**(HTML)+ **reportlab**(PDF) | reportlab 是纯 Python 实现,不需要系统库 | | 前端 | **原生 JS + Tailwind (CDN)** | 无构建步骤;整个应用通过 `uvicorn` 运行 | | 监控 | **sentry-sdk ≥ 2.61**(可选) | 这个版本*不会*在 Python 3.13 上崩溃 | | 测试 | **pytest** | 完全离线运行 | | CI | **GitHub Actions**(3.11 / 3.12 / 3.13 矩阵) | 提早发现驱动/运行时的破坏性更改 | 全部开源。全部是标准技术。没有任何非主流的异类。 ## 🔍 检查项(全部九大类别) 每一项发现的状态为 `pass` / `warn` / `fail` / `info`,包含严重程度和权重,并且(如果失败)会附带具体的修复方案和 OWASP Top-10 映射。 ### 1. TLS & 传输层 (`tls`) - 站点可通过 HTTPS 访问 - 协商了现代的 TLS 协议(TLS 1.2 / 1.3) - 证书处于有效期内(过期时间 + 颁发者) - 普通 HTTP 重定向到 HTTPS ### 2. 安全标头 (`headers`) - 存在 `Strict-Transport-Security`(HSTS),且 `max-age` 设置合理 - 存在 `X-Content-Type-Options: nosniff` - 点击劫持防护(`X-Frame-Options` **或** CSP `frame-ancestors`) - `Referrer-Policy` 设置为保护隐私的值 - 存在 `Permissions-Policy` - 存在 `Cross-Origin-Opener-Policy` - 未泄露软件版本号(`Server` / `X-Powered-By`) ### 3. 内容安全策略 (`csp`):*深度分析* - 存在 CSP 标头 - script 上下文中没有 `'unsafe-inline'` - 没有 `'unsafe-eval'` - 定义了 `default-src` 回退机制 - `object-src 'none'`(禁用插件) - 没有通配符(`*`)来源 ### 4. Cookie (`cookies`) - 每个 `Set-Cookie` 都设置了 `Secure`、`HttpOnly` 和 `SameSite` ### 5. DNS 与邮件认证 (`dns_email`) - 发布了 **DMARC** 策略(且未停留在 `p=none`) - 发布了 **SPF** 记录 - **CAA** 记录限制了证书签发 - 启用了 **DNSSEC**(建议项) ### 6. 重定向 (`redirects`) - 重定向链长度合理 - 链路中任何地方都没有 HTTPS→HTTP 降级 ### 7. 混合内容 (`mixed_content`) - `https://` 页面上没有引用 `http://` 资源 ### 8. HTTP 协议 (`http_protocol`) - 使用现代 HTTP 协议(HTTP/2 或 HTTP/3) ### 9. 信息披露与 `.well-known` (`wellknown`) - 根据 RFC 9116 发布了 `security.txt` ## 🧮 评分标准 评级绝不黑盒。完整的评分标准也会通过 **`GET /api/meta`** 实时提供。 **状态得分率**(每种状态能获得该项发现权重的多少): | status | 得分率 | |---|---| | `pass` | 100% | | `info` | 不参与计分(仅供上下文参考) | | `warn` | 50% | | `fail` | 0% | **类别分数** = 在该类别的各项发现中计算 `sum(权重 × 得分率) / sum(权重)`。 **类别权重**(在最终评级中的相对重要性): | category | 权重 | |---|---| | `tls` | 2.0 | | `headers` | 2.0 | | `csp` | 1.5 | | `dns_email` | 1.5 | | `cookies` | 1.0 | | `redirects` | 1.0 | | `mixed_content` | 1.0 | | `http_protocol` | 0.5 | | `wellknown` | 0.5 | **总得分** = 类别分数的加权平均值 × 100。 **评级区间:** A+ ≥ 95 · A ≥ 90 · B ≥ 80 · C ≥ 70 · D ≥ 60 · F < 60。 *计算示例:* 一个网站除了缺少 HSTS(在 `headers` 类别中算作一次 `fail`,权重 2.0)之外,其他所有项都完美通过,它将失去 `headers` 分数的一部分,然后该部分在平均值中的加权为 2.0。因此,单个高价值项目的缺失会明显拉低评级,完全符合预期设计。 ## ⚡ 快速开始 **前置条件:** Python 3.11+(支持 3.13)。就这些:不需要 Node,不需要数据库服务器,不需要云账户。 ``` # 1. clone / 进入项目 cd AegisScan # 2. 创建 virtual environment python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate # 3. install pip install -r requirements.txt # 4. (可选)复制 env 默认配置;app 也可以在没有 .env 的情况下运行 cp .env.example .env # 5. run uvicorn app.main:app --reload ``` 现在打开浏览器访问: - **http://127.0.0.1:8000/**:应用主页(可扫描某个域名) - **http://127.0.0.1:8000/docs**:交互式 API 文档 - **http://127.0.0.1:8000/api/health**:健康检查 通过命令行扫描: ``` curl -X POST http://127.0.0.1:8000/api/scans \ -H "Content-Type: application/json" \ -d '{"hostname": "github.com"}' ``` ### 或者使用 Docker 运行 ``` docker build -t aegisscan . docker run -p 8000:8000 aegisscan ``` ### 针对 Postgres 运行(模拟生产环境设置) ``` docker compose up # starts Postgres + the API wired together ``` ## ⚙️ 配置 每一个配置项都有安全的默认值;本应用在 **没有 `.env` 文件** 的情况下即可运行。你可以通过环境变量(均以 `AEGIS_` 为前缀) `.env` 文件进行覆盖。详情请参见 `.env.example`。 | 变量 | 默认值 | 用途 | |---|---|---| | `AEGIS_ENV` | `development` | `development` / `staging` / `production` | | `AEGIS_SECRET_KEY` | 开发占位符 | **在任何部署中都必须更改**;用于签发 JWT | | `AEGIS_DATABASE_URL` | `sqlite:///./aegisscan.db` | SQLite 或 `postgresql+psycopg://…` | | `AEGIS_CORS_ALLOW_ORIGIN_REGEX` | localhost + `*.vercel.app` | 一个正则表达式即可匹配所有预览主机 | | `AEGIS_SCAN_TIMEOUT_SECONDS` | `10` | 单次探测的网络超时时间 | | `AEGIS_ALLOW_PRIVATE_TARGETS` | `false` | **在生产环境中绝对不能设为 `true`**(防范 SSRF) | | `AEGIS_RATE_LIMIT_PER_MINUTE` | `20` | 针对单个 IP 的扫描提交频率限制 | | `AEGIS_PUBLIC_BENCHMARKS` | github, stripe, … | 在仪表盘上展示且不进行掩码处理的主机名 | | `AEGIS_SENTRY_DSN` | 空 | 可选的错误监控 | 生成真实的密钥: ``` python -c "import secrets; print(secrets.token_urlsafe(48))" ``` ## 🔌 REST API 参考 完整的交互式文档位于 **`/docs`**(Swagger)和 **`/redoc`**。API 概览: | 方法 | 路径 | 认证 | 描述 | |---|---|---|---| | `GET` | `/api/health` | – | 存活状态 + 版本 | | `GET` | `/api/meta` | – | 评分标准 + 类别列表 | | `POST` | `/api/auth/register` | – | 创建账号 | | `POST` | `/api/auth/login` | – | 获取 JWT(OAuth2 密码表单) | | `GET` | `/api/auth/me` | ✅ | 获取当前用户 | | `POST` | `/api/scans` | 可选 | 发起扫描(访客或已认证用户) | | `GET` | `/api/scans` | ✅ | 你的扫描历史记录 | | `GET` | `/api/scans/{id}` | – | 获取某次扫描(完整结果) | | `GET` | `/api/scans/compare?before=&after=` | – | 对比同一主机的两次扫描差异 | | `GET` | `/api/scans/{id}/report.html` | – | 独立的 HTML 报告 | | `GET` | `/api/scans/{id}/report.pdf` | ✅ | PDF 报告(认证用户的额外特权) | | `GET` | `/api/dashboard` | – | 公共汇总统计(主机名已掩码) | | `GET/POST/DELETE` | `/api/domains` | ✅ | 跟踪你关注的域名 | 访客与已认证用户的区别与 PostureScan 一致:任何人都可以进行扫描;而拥有账户则可解锁历史记录、域名跟踪、扫描对比以及 PDF 导出功能。 ## 📄 报告 每次扫描都可以通过三种方式呈现: - **JSON**:原始的 `POST /api/scans` 响应或 `GET /api/scans/{id}`。机器可读;可直接放入你自己的 CI pipeline 中。 - **HTML**:`GET /api/scans/{id}/report.html`。一个干净、独立的页面。 - **PDF**:`GET /api/scans/{id}/report.pdf`(需认证)。使用 reportlab 生成,因此**无需安装任何系统库**(这是 HTML 转 PDF 工具常见的痛点)。 ## 🔒 安全模型与 SSRF 防护 一个会抓取用户提供的 URL 的扫描器天生带有 SSRF 风险。AegisScan 进行了深度防御(`app/guard.py`): - 主机名会被标准化,且明显的本地名称(`localhost`、`*.local`)会被直接拒绝。 - 主机名会被解析,并且会检查**每一个**解析出的 IP。只要其中任何一个属于私有、环回、链路本地、多播、保留或未指定地址,该扫描就会被拒绝。 - 所有探测都仅限于 **只读** 的 `GET` 流量,并带有固定的、可识别的 User-Agent。 - 基于单 IP 的速率限制可防止滥用。 `AEGIS_ALLOW_PRIVATE_TARGETS=true` 的存在仅仅是为了让你扫描**自己的**实验室环境,绝不能在公开部署中启用。 ## 🧪 测试 测试套件 **完全离线运行**:唯一的一处扫描成功路径测试 monkeypatch 了执行引擎,且防护测试 monkeypatch 了 DNS 解析。全程不会连接任何真实的主机。 ``` pytest -q ``` 测试覆盖范围: - `test_scoring.py`:评级区间、警告 = 一半分数、info 排除在外、类别加权 - `test_guard.py`:标准化 + 拦截私有/环回 IP 的 SSRF 防护 - `test_masking.py`:仪表板主机名掩码处理 + 基准测试白名单 - `test_checks.py`:针对合成探测数据的单独检查项测试 - `test_api.py`:健康检查、元数据、注册/登录、校验、扫描持久化、认证网关、域名跟踪 CI 会在每次推送到 `main` 或 `staging` 分支时,在 Python **3.11、3.12 和 3.13** 的矩阵环境中运行这些测试(`.github/workflows/ci.yml`)。 ## 🗂️ 项目结构 ``` AegisScan/ ├── app/ │ ├── main.py FastAPI app: CORS, routers, serves the SPA, /docs │ ├── config.py env-driven settings (safe defaults) │ ├── database.py SQLAlchemy engine/session (SQLite or Postgres) │ ├── models.py User, Scan, TrackedDomain │ ├── schemas.py pydantic request/response models │ ├── auth.py JWT + bcrypt, guest/auth dependencies │ ├── guard.py SSRF guard + hostname normalization │ ├── scoring.py weights, status credit, grade bands │ ├── masking.py privacy-aware hostname masking │ ├── reporting.py HTML (Jinja2) + PDF (reportlab) │ ├── ratelimit.py per-IP sliding window │ ├── routers/ auth · scans · dashboard · domains │ └── engine/ │ ├── runner.py orchestrates guard → probe → evaluate → score │ ├── base.py Finding / ProbeContext types │ └── checks_*.py one module per category (pure functions) ├── web/ index.html + app.js (the SPA) ├── tests/ pytest suite (offline) ├── .github/workflows/ CI ├── Dockerfile · docker-compose.yml ├── requirements.txt · .env.example · .gitignore · LICENSE └── README.md ``` ## 🚢 部署与 CI/CD AegisScan 保留了 PostureScan 流水线中行之有效的部分,并去除了曾坑过他们的地方。 **分支模型(已保留):** 在 `staging` 上进行开发,然后通过 **仅限快进** 的方式合并到 `main`。因此,`main` 永远是 `staging` 的严格祖先,没有合并提交,也没有分叉。在合并(提升)之前,CI 必须是绿通状态。 **数据库迁移(已修复):** PostureScan 的数据库迁移会静默失效,因为 Nixpacks 构建器忽略了 Procfile 中的 release 命令行。AegisScan 在启动时会为 SQLite 自动创建表;而对于 Postgres,你需要在一个明确的 pre-deploy 钩子中运行 Alembic(例如 Railway 的 `railway.json` 中的 `preDeployCommand`,或者在你容器的 entrypoint 中执行 `alembic upgrade head`),绝不依赖隐式的 Procfile 命令行。 **CORS(已修复):** 仅使用一条 **正则表达式**(regex)规则(`AEGIS_CORS_ALLOW_ORIGIN_REGEX`)即可匹配每一个临时的预览主机名,因此预览部署永远不会被拒绝。 **驱动/运行时(已修复):** 锁定了 `psycopg` v3(提供 Python-3.13 wheels)和 `sentry-sdk` ≥ 2.61,提前规避了原项目遇到的两次崩溃。 典型的托管设置:在任何支持运行 Dockerfile 的平台(Railway、Fly、Render、Cloud Run)上运行容器(即本代码库),搭配一个托管的 Postgres 数据库(Supabase/Neon/RDS),以及可选的 Sentry。由于前端由同一个进程提供服务,因此不需要同步维护单独的前端部署。 ## 🛣️ 路线图 - 定期重新扫描,并在被跟踪域名的评级下降时发送邮件提醒 - 更多类别:证书透明度、IPv6 可达性、更深度的 CSP nonce/hash 校验 - 除了 OWASP 之外,将发现结果映射到合规框架(PCI-DSS、SOC 2) - 开发一款浏览器插件,在你浏览时显示当前网站的评级 - 多区域扫描,以捕获 CDN/特定区域的连通性问题 - 基于 Redis 的速率限制 + 针对多实例部署的结果缓存 ## ⚖️ 负责任地使用 AegisScan 仅对外部可达的 endpoint 执行 **被动的、只读的检查**。请勿将其指向你不拥有或未获得明确测试授权的系统。SSRF 防护默认拦截私有地址空间;在任何共享部署环境中,请务必保持此设置。 ## 📜 许可证 MIT。详见 [`LICENSE`](./LICENSE)。 *AegisScan 站在了 PostureScan 的肩膀上。感谢那个团队提出了尖锐的问题,并如实记录了哪些地方出了问题;这里的一些修复方案之所以存在,正是因为他们的幻灯片如此清晰地记录了那些失败。*
标签:AV绕过, Docker, FastAPI, 安全防御评估, 实时处理, 密码管理, 异步扫描, 特征库, 聊天机器人, 请求拦截, 运行时操纵, 逆向工具