vurs/capstone-vulnerability-scanner
GitHub: vurs/capstone-vulnerability-scanner
一款动态应用安全测试(DAST)工具,对已部署的 Web 应用进行自动化黑盒漏洞扫描并生成报告。
Stars: 0 | Forks: 0
# 毕业设计漏洞扫描器
我们毕业设计项目的漏洞扫描器部分。
旨在与相关的 [Spring Boot 测试 Web 应用](https://github.com/vurs/capstone-test-website-spring) 配合使用。该扫描器还支持其他目标,包括用于 SPA 测试的 [OWASP Juice Shop](https://github.com/juice-shop/juice-shop)。
### 项目概述
我们的团队正在构建一个动态应用安全测试(DAST)工具,用于对 Web 应用执行自动化扫描、注入构造的 payload、识别 Web 漏洞,并生成用户友好的报告,解释发现的漏洞并提供修复建议。
请注意,这并不是一个像 Checkmarx、SonarQube、Semgrep 或其他静态应用安全测试(SAST)工具那样扫描源代码的工具。这是一个扫描已部署的实际应用程序的工具,本质上是一种自动化的黑盒渗透测试,其 payload 能够从前端穿透到后端,以识别诸如 SQLi 和命令注入等漏洞。
我们旨在为该扫描器开发一款桌面应用程序,开发人员可以借此手动配置并在他们实际的 Web 应用上运行扫描。此外,DAST 的一个主要优势是它可以集成到 CI/CD pipeline 中以自动扫描代码变更,因此我们还将提供一个 GitHub Actions Workflow,开发团队可以将其导入到自己的 GitHub 仓库中,并配置按计划执行、或在每次合并到 main 分支时执行、或按他们选择的任何灵活时间表执行的扫描。
### 设置和安装说明
1. 克隆仓库
2. 在仓库目录下,运行 `python dev_scripts/setup_dev.py` 来创建项目 `.venv`、安装依赖并配置 git hooks。设置完成后,如果 `.venv` 丢失、requirements 发生变化或 packages 不完整,pre-commit hook 将阻止提交。发生这种情况时,请重新运行 `setup_dev.py`。
3. 激活虚拟环境:
* macOS/Linux: `source .venv/bin/activate`
* Windows: `.venv\Scripts\activate`
如需仅安装运行时的依赖,请激活 `.venv` 并运行 `pip install -r requirements.txt`。
浏览器抓取模式(`--crawl-mode browser` 或 `both`)需要 Google Chrome 以及 Selenium 可用的兼容 ChromeDriver。
### 运行扫描
#### 桌面应用程序
从项目根目录启动 PySide6 UI:
```
python ui/app.py
```
仪表板包含 **Web** 和 **API(仅限 OpenAPI)** 扫描模式。在 API 模式下,设置目标 URL 和可选的 OpenAPI spec 路径(例如 `/v3/api-docs`);抓取模式将被隐藏。
在 **Authentication** 页面,针对标准的 HTML 表单或 JSON API 登录选择 **Automatic**,或者当自动认证无法处理目标时(例如多步骤登录或 OAuth 风格的流程)选择 **Custom login script**。脚本构建器允许您定义 HTTP 步骤、从响应中提取值(token、表单动作、CSRF 字段)、在扫描前测试登录,以及将脚本保存到 `data/auth_scripts/` 下的磁盘库中。脚本中的登录字段值被引用为 `{{field_name}}`(例如 `{{email}}` 或 `{{username}}`)。配置可选的 **session probe URL**,以便在 session 过期时,扫描器可以在扫描过程中重新运行相同的认证方法。
#### 命令行
**未认证扫描(传统 HTML 站点):**
```
python main.py http://127.0.0.1:8081
```
**认证扫描(HTML 登录表单):**
```
python main.py http://127.0.0.1:8081 http://127.0.0.1:8081/post-list \
--auth-field username=testuser \
--auth-field password=password
```
仍然支持旧版位置参数 username/password:
```
python main.py http://127.0.0.1:8081 http://127.0.0.1:8081/post-list testuser password
```
**SPA / JSON API 登录(例如 OWASP Juice Shop):**
使用 `browser` 或 `both` 抓取模式,以便发现客户端渲染的路由。根据需要配置 API 登录和 session 探测:
```
python main.py http://127.0.0.1:3000 http://127.0.0.1:3000/#/login \
--auth-field email=capstone-test@example.com \
--auth-field password=CapstoneTest123! \
--auth-api-url /rest/user/login \
--auth-session-probe-url /rest/user/whoami \
--auth-session-probe-json-field user.id \
--crawl-mode browser
```
可选的认证 flags:
| Flag | 用途 |
|------|---------|
| `--auth-field NAME=VALUE` | 登录字段(每个字段重复一次) |
| `--auth-method` | `automatic`(默认)或 `script`(自定义多步骤登录脚本) |
| `--auth-script` | JSON 认证脚本文件的路径(需要 `--auth-method script`) |
| `--auth-api-url` | 当登录页面没有 HTML 表单时的 JSON 登录 API 路径或 URL |
| `--auth-session-probe-url` | 用于检测过期 session 的 endpoint |
| `--auth-session-probe-json-field` | 可选的点分 JSON 路径,必须在成功的探测响应中存在 |
| `--crawl-mode` | `http`(默认)、`browser` 或 `both` |
| `--scan-profile` | `web`(默认;抓取 + 表单 + 可选 API 发现)或 `api`(仅限 OpenAPI,无抓取) |
| `--openapi-url` | 显式的 OpenAPI spec 路径或 URL(例如 `/v3/api-docs`) |
| `--openapi-file` | 本地 OpenAPI JSON/YAML 文件(离线;与 `--openapi-url` 互斥) |
| `--api-discovery` | 用于 web/SPA 扫描的 REST API endpoint 发现:`auto`(检测到 Juice Shop seeds 时使用 + 查询参数 + 网络 + OpenAPI)、`generic`(无 seeds;查询参数 + 网络 + OpenAPI)、`juice-shop`(强制 seeds)或 `off`。当为 `--scan-profile api` 时被忽略。 |
当未配置 session 探测 URL 时,扫描器将跳过扫描过程中的自动重新认证。
**自定义登录脚本(多步骤认证):**
在自动表单/API 登录不充足时使用。提供一个 JSON 脚本文件,并为脚本中使用的任何 `{{variable}}` 引用设置登录字段(在早期步骤中由提取规则生成的变量不需要登录字段)。
```
python main.py http://127.0.0.1:8081 \
--auth-method script \
--auth-script ./data/auth_scripts/my-login.json \
--auth-field username=testuser \
--auth-field password=password \
--auth-session-probe-url /rest/user/whoami
```
对于 Web 扫描,在解析脚本步骤路径时,目标 URL 被用作主机基础。设置 `--auth-session-probe-url`(以及可选的 `--auth-session-probe-json-field`)以启用扫描过程中的重新认证;当探测指示 session 已过期时,相同的脚本将再次运行。
API 发现(非 `off` 状态时)在检测到时会植入已知的 Juice Shop REST 路由作为 seeds,在浏览器模式下从抓取的 URL 中提取查询参数,在浏览器抓取期间捕获 XHR/fetch 流量,并针对 Spring Boot 风格的后端探测常见的 OpenAPI spec 路径。
**仅 API 扫描(REST 后端,无 HTML 前端):**
使用 `--scan-profile api` 跳过抓取并从 OpenAPI spec 中发现 endpoint。这旨在用于像 [Spring Boot 测试 Web 应用](https://github.com/vurs/capstone-test-website-spring) 这样公开 `/v3/api-docs` 的后端。
```
python main.py http://127.0.0.1:8081 \
--scan-profile api \
--openapi-url /v3/api-docs
```
经过认证的仅 API 扫描(不需要 HTML 登录页面):
```
python main.py http://127.0.0.1:8081 \
--scan-profile api \
--openapi-url /v3/api-docs \
--auth-api-url /api/auth/login \
--auth-field username=testuser \
--auth-field password=password
```
离线 spec(从磁盘加载文档;目标主机仍用于注入请求):
```
python main.py http://127.0.0.1:8081 \
--scan-profile api \
--openapi-file ./openapi.json
```
有关架构和未来阶段的信息,请参阅 [docs/api-scanning-plan.md](docs/api-scanning-plan.md)。
**针对 Spring Boot 测试应用的手动验证:**
1. 在 [capstone-test-website-spring](https://github.com/vurs/capstone-test-website-spring) 仓库中,运行 `docker compose up --build`。
2. 确认 OpenAPI spec 可访问:`http://127.0.0.1:8081/v3/api-docs`
3. 运行上面的仅 API 扫描命令。
4. 确认扫描日志通过 OpenAPI 发现列出了 `/users/search` 和 `/network/ping`,并在不抓取的情况下完成。
5. 查看 `data/reports/` 下生成的报告。
#### 本地 Juice Shop 测试目标
要在本地启动带有测试用户的 Juice Shop:
```
node dev_scripts/deployments/start_juice_shop.js
```
#### 单元测试
快速回归测试位于 `tests/unit/` 下。默认情况下排除集成测试。
```
pytest tests/unit/
```
CI 通过 `.github/workflows/unit-tests.yml` 在每次推送到 `main` 和 pull request 时运行单元测试。
#### 集成测试
端到端回归测试位于 `tests/` 下。它们默认被跳过;当合适的目标正在运行时,请传递 `--run-integration`。
**Juice Shop**(端口 3000,浏览器抓取 + 网络发现):
```
pytest --run-integration tests/integration/test_juice_shop_scan.py tests/integration/test_juice_shop_network_discovery.py
```
```
python dev_scripts/verify_juice_shop_scan.py
```
CI 通过 `.github/workflows/integration-tests.yml` 运行 Juice Shop 测试(Docker Juice Shop + headless Chrome)。
关闭 seeds 的测试(`test_juice_shop_network_discovery.py`)使用 `--api-discovery generic`,以确认 `/rest/products/search` 是在没有 Juice Shop seeds 的情况下通过浏览器网络捕获发现的。
**Spring Boot 测试应用**(端口 8081,仅 API OpenAPI 扫描):
1. 在 test-website-spring 仓库中启动 Spring 应用:`docker compose up --build`。
2. 运行:
```
pytest --run-integration tests/integration/test_openapi_api_scan.py
```
可选的自定义 base URL:
```
pytest --run-integration --spring-api-url http://127.0.0.1:8081 tests/integration/test_openapi_api_scan.py
```
等效的 CLI 封装:
```
python dev_scripts/verify_spring_api_scan.py
```
此测试确认了从 `/v3/api-docs` 进行的 OpenAPI 发现、在 `GET /users/search` 上的 SQLi 检测、在 `GET /users/profile` 上的 IDOR 检测以及报告生成。CI 在 `.github/workflows/integration-tests.yml` 的专用 Spring 作业中运行这些测试。
**DVWA**(端口 4280,HTML 表单登录和自定义认证脚本):
```
pytest --run-integration tests/integration/test_dvwa_scan.py
```
CI 通过 `.github/workflows/integration-tests.yml` 运行 DVWA 测试(Docker DVWA 镜像)。
#### GitHub Actions workflow
团队可以将计划的或事件驱动的扫描导入到他们自己的仓库中。该扫描器提供了一个可重用的 workflow 和一个可复制粘贴的示例。
**快速开始(可重用 workflow):**
1. 将 `examples/workflows/capstone-vulnerability-scan.yml` 作为 `.github/workflows/capstone-vulnerability-scan.yml` 复制到您的仓库中。
2. 将仓库变量 `SCAN_TARGET_URL` 设置为您部署的应用程序 URL(例如 `https://staging.example.com`)。
3. 可选择性地设置仓库 secret `SCAN_AUTH_FIELDS`,内容为 JSON 格式的登录字段,例如 `{"username":"alice","password":"secret"}`。
4. 在 workflow 文件中调整触发器(`schedule`、`pull_request`、`push`)和扫描选项。
可重用的 workflow(`.github/workflows/capstone-scan.yml`)检出扫描器、安装依赖项、运行 `dev_scripts/ci/run_scan.py`,并将 PDF 报告作为 workflow artifact 上传。
**CI 中的认证:**
- **Automatic**(默认):使用 `SCAN_AUTH_FIELDS` 的 HTML 表单登录或 JSON API 登录,以及可选的 `auth-api-url`、`auth-session-probe-url` 和 `auth-session-probe-json-field` workflow 输入。
- **Custom script**:将 `auth-method: script` 和 `auth-script-path` 设置为您仓库中的 JSON 文件(参见 `examples/auth-scripts/dvwa-login.json`)。使用与桌面应用程序相同的声明式步骤格式。
**示例配置:**
| 目标 | Profile | 抓取模式 | 认证 |
|--------|---------|------------|------|
| Spring Boot API | `api` | (忽略) | 可选的 JSON API 登录 |
| OWASP Juice Shop | `web` | `browser` | 自动 API 登录 + session 探测 |
| DVWA | `web` | `http` | 自动表单登录或自定义脚本 |
**CI 环境变量**(由 `dev_scripts/ci/run_scan.py` 使用):
| 变量 | 用途 |
|----------|---------|
| `SCAN_TARGET_URL` | 必需的目标 base URL |
| `SCAN_LOGIN_URL` | 用于经过认证的 Web 扫描的登录页面 |
| `SCAN_AUTH_FIELDS` | 登录字段值的 JSON 对象 |
| `SCAN_AUTH_METHOD` | `automatic`(默认)或 `script` |
| `SCAN_AUTH_SCRIPT_PATH` | workspace 中自定义认证脚本 JSON 的路径 |
| `SCAN_AUTH_API_URL` | 用于 SPA 的 JSON 登录 endpoint |
| `SCAN_SESSION_PROBE_URL` | session 有效性探测 endpoint |
| `SCAN_SESSION_PROBE_JSON_FIELD` | 用于探测成功的点分 JSON 路径 |
| `SCAN_CRAWL_MODE` | `http`、`browser` 或 `both` |
| `SCAN_PROFILE` | `web` 或 `api` |
| `SCAN_OPENAPI_URL` | 用于仅 API 扫描的 OpenAPI spec 路径 |
| `SCAN_API_DISCOVERY` | `auto`、`generic`、`juice-shop` 或 `off` |
| `SCAN_FAIL_ON_FINDINGS` | 设置为 `true` 时,如果记录了发现结果则使作业失败 |
| `SCAN_NOTIFY_WEBHOOK_URL` | 用于扫描摘要的通用 JSON webhook URL |
| `SCAN_NOTIFY_SLACK_WEBHOOK` | 用于扫描摘要的 Slack 传入 webhook URL |
| `SCAN_NOTIFY_TEAMS_WEBHOOK` | 用于扫描摘要的 Microsoft Teams 传入 webhook URL |
| `SCAN_NOTIFY_MIN_SEVERITY` | 通知的最低严重级别:`critical`、``、`medium` 或 `low` |
| `SCAN_REPORT_URL` | 通知中包含的可选报告链接。在大多数 workflow 中手动设置;Spring 测试应用 workflow 在上传后会自动设置预签名的 S3 URL。 |
每次 CI 扫描后,`run_scan.py` 会写入:
- `reporting/output/capstone-findings.json` — 结构化结果导出
- `reporting/output/capstone-findings.sarif` — 用于 GitHub Code Scanning 的 SARIF
可重用的 workflow 将 SARIF 上传到 **Security → Code scanning alerts**(私有仓库需要 GitHub Advanced Security),并能在配置了上述 webhook secret 后发送通知。
为了上传 SARIF,请在被扫描的仓库中的 `.github/capstone-dast-locations.txt` 处提交一个存根清单。CI 扫描会用每个发现结果对应的一行内容覆盖此文件,以便 GitHub Code Scanning 可以将警报附加到仓库文件路径。
**可重用 workflow 输入**(`.github/workflows/capstone-scan.yml`):
| 输入 | 用途 |
|-------|---------|
| `upload-sarif` | 将 SARIF 上传到 GitHub Code Scanning(默认:`true`) |
| `notify-min-severity` | webhook 通知中包含的最低严重级别(默认:`medium`) |
**用于通知的可选仓库 secret:**
| Secret | 用途 |
|--------|---------|
| `SCAN_NOTIFY_WEBHOOK_URL` | 通用 JSON webhook |
| `SCAN_NOTIFY_SLACK_WEBHOOK` | Slack 传入 webhook |
| `SCAN_NOTIFY_TEAMS_WEBHOOK` | Microsoft Teams workflow/connector URL |
有关 Slack 和 Teams webhook 设置步骤,请参阅 [docs/ci-notification-setup.md](docs/ci-notification-setup.md)。
使用以下命令重新生成该指南:
```
python dev_scripts/ci/generate_webhook_setup_docs.py
```
针对 Juice Shop、Spring 和 DVWA 的 workflow 验证在 `.github/workflows/scan-workflow-validation.yml` 中运行。
### 当前项目状态
目前创建了以下功能:
* 扫描器第 1 阶段:Crawler/Spider(HTTP 和 browser/Selenium 模式)
* 扫描器第 2 阶段:Payload 注入器
* 扫描器第 3 阶段:漏洞验证器
* 扫描器第 4 阶段:报告生成器
* 反射型和存储型 XSS payload
* SQL 注入 payload(差分和基于错误的检测)
* 命令注入 payload
* 安全标头配置错误检查
* 损坏的访问控制(IDOR)检查——在抓取的 URL、表单和发现的 REST endpoint 上进行资源 ID 篡改
* 暴露的目录和敏感文件检查
* 用于测试扫描器的存在漏洞的测试 Web 应用程序
* HTML 表单登录和 JSON API 登录的认证(SPA 友好)
* 自定义登录脚本构建器(桌面 UI),具备测试登录、磁盘脚本库和 JSON 导入功能
* 声明式多步骤认证脚本的 CLI 支持(`--auth-method script`、`--auth-script`)
* 基于 session 探测的重新认证(自动和脚本认证共享相同的探测逻辑)
* 针对感知 Hash-route 的 SPA 浏览器抓取
* 漏洞扫描器的基础桌面应用程序(Web 和 API 扫描模式)
* 具有 OpenAPI endpoint 发现功能的仅 API 扫描 profile(`--scan-profile api`)
* 针对发现的 REST endpoint 进行 SQLi、XSS 和命令注入的 API 注入
* 针对 SPA 后端的 REST/API endpoint 发现(Juice Shop seeds、查询参数 URL、浏览器网络捕获、OpenAPI)
* 用于计划和事件驱动扫描的 GitHub Actions 可重用 workflow,支持自动和自定义脚本认证
* 用于 GitHub Code Scanning(Security 选项卡)的 SARIF 导出和 CI webhook 通知(通用、Slack、Microsoft Teams)
### 仍在进行中的功能
以下功能正在进行中:
* 额外的 payload(缓冲区溢出、无 Anti-CSRF Tokens 等)
* 增强漏洞扫描器的桌面应用程序功能
* API endpoint 上的速率限制和节流检测
### 已知问题和限制
* **传统 HTML 站点**最适合使用 HTTP 抓取模式。
* **仅 API 扫描**需要通过 `--openapi-url`、`--openapi-file` 或诸如 `/v3/api-docs` 之类的知名路径获取 OpenAPI spec。没有参数的操作会被跳过;在第一阶段中不解析 `$ref` schema。
* **SPA** 需要 browser 抓取模式来发现客户端渲染的路由和基于 Hash 的导航(例如 `#/about`)。REST API endpoint 通过 seeds、查询参数、浏览器网络捕获和 OpenAPI spec 发现;针对这些 endpoint 的注入与 HTML 表单分开运行。
* **Session 探测**是可选的。执行认证扫描的目标应公开一个探测 endpoint(例如 `/api/session/me`),在注销时返回 `401`/`403`;或者当探测在两种状态下都返回 `200` 时,配置 `--auth-session-probe-json-field`。同样的探测机制驱动着自动和自定义脚本认证的重新认证。
* **自定义登录脚本**使用声明式 JSON 步骤格式(HTTP 请求、响应提取、cookie 捕获)。它们旨在作为自动认证失败时的后备方案;目前不支持 bearer-token header 认证(通过脚本提取或自动 API 登录支持将 JWT 作为 cookie 使用)。
* **Browser 模式**需要 Selenium 和 Chrome。覆盖层、cookie 横幅和繁重的客户端渲染在某些应用程序中仍然会限制链接发现。
* **损坏的访问控制检查**使用单 session 启发式方法(基线与对等 ID 重放)。它们不会将两个已认证的用户进行并排比较,并且当对等响应与基线一致或无法从抓取/API metadata 中发现 ID 时,可能会漏掉 IDOR。
* **仅 API 模式下的损坏访问控制**不使用硬编码的 endpoint 路径。Endpoint 必须出现在 OpenAPI spec 中(或者在 `web` 模式下的其他 API 发现源中)。对于具有类 ID 名称(例如 `userId`)的查询或路径参数,扫描器需要该参数上有 OpenAPI 的 `example` 或 `default`,以便它可以在 `benign_defaults` 中保存基线值并重放对等 ID。spec 中列出但没有 example/default 的路由可能会被发现以进行注入,但会被 BAC 跳过。在 `web` 模式下,仍然可以在没有 OpenAPI metadata 的情况下探测嵌入在抓取的 URL 或表单中的数字 ID。
### 相关文档、图表和演示的链接
* [团队 Jira](https://sheridan-cyber-capstone-2026.atlassian.net/jira/software/projects/SCRUM/boards/1)(与我联系以获取访问权限)
* [第 2 阶段的修订项目计划](https://sheridan-cyber-capstone-2026.atlassian.net/wiki/x/AQD-AQ)(与我联系以获取访问权限)
* [系统架构图](https://drive.google.com/file/d/15G35238mbmTRRoIVubBf7kuU-v8xIKI9/view?usp=sharing)
* [仓库贡献分布](https://github.com/vurs/capstone-vulnerability-scanner/graphs/contributors)
* 项目演示即将推出...
标签:CISA项目, DAST, DevSecOps, LNA, Python, Web安全, 上游代理, 安全测试, 恶意软件分析, 攻击性安全, 无后门, 蓝队分析, 请求拦截, 逆向工具