Zaffri/sast-scanner
GitHub: Zaffri/sast-scanner
一个基于事件驱动架构的静态应用安全测试(SAST)流水线项目,支持上传代码库并自动使用 Semgrep 进行安全漏洞扫描与结果可视化。
Stars: 0 | Forks: 0
# SAST Scanner








一个用于静态应用安全测试(SAST)的事件驱动 pipeline。旨在接收并自动扫描上传的代码库,以提供安全报告摘要。

_(展示 DVWA (Damn Vulnerable Web Application) 被上传并扫描的演示)_
## 功能
* 文件上传:用户可以 ZIP 格式上传他们的项目,并存储在类似 S3 的存储(Garage)中。
* 异步扫描任务:worker 从队列中提取待处理的扫描任务,并在后台按照自己的节奏进行扫描。
* 安全扫描:worker 解压项目并使用 Semgrep 来识别安全发现。
* 持久化与可观测性:安全发现存储在数据库中。Grafana 仪表板用于展示简单的运维指标和安全洞察。Prometheus 和 Loki 用于转发日志并向 Grafana 暴露指标。
* React 前端,用户可以登录、上传项目/代码库进行扫描并查看结果。
_注意:该项目仍在开发中。目前功能有限,请参阅下方的“未来新增功能/已知问题”标题。_
## 系统设计与技术栈
_包含通用组件和系统设计的高层级架构图。_

### API
主 API 使用 Python 编写,具体来说是基于 Django 的。它让我能够快速上手。它给人一种“开箱即用且功能齐全”的体验。我还借此练习了 Python,这是个加分项。此外还有一些很棒的 Django 包,比如我用于实现 outbox pattern 的 `django-outbox-pattern`,实现起来超级简单。
### Worker 与扫描
Worker 基于 Node.js。坦白说,之所以这么决定,是因为最初我打算纯粹专注于 JS/TS 项目,并使用 AST 来识别潜在问题。因此,Node.js 是我最初计划的显而易见之选。然而,在开发过程中,我决定使用一套现成的扫描解决方案,它经过实战检验,并且能够支持不同类型的项目,而不仅仅是 JS。正因为如此,我选择了 Semgrep。
未来我希望增加额外的安全步骤/检查来补充 Semgrep,希望能借此改善扫描结果。所以从技术上讲,worker 已经不再必须基于 Node.js 了,它可以很容易地被替换。我所选择的消息中间件允许我构建技术无关的 worker,因此如果某个步骤需要特定的语言或工具,这完全没问题。
### 消息中间件
我之所以在这里选择 RabbitMQ,是因为它很受欢迎、有良好的支持、不仅仅是一个简单的队列(对未来的发展有益),而且它允许我在需要时使用不同技术/语言编写 worker/消费者。启动和运行也相当快,不需要折腾大量的配置。
### 对象存储
我希望能轻松存储 ZIP 文件,并且为了本地开发的目的,能在容器中运行这套存储服务。市面上有几种解决方案可以实现这一点,我选择 Garage 是因为它是开源的并且兼容 S3——这意味着在生产环境中我们可以使用任何兼容 S3 的存储,也就是说不一定非得是 Garage。与其他一些已经归档的解决方案相比,它似乎也仍在积极维护中。
## 快速开始
所有的服务都由 docker compose 管理,你需要确保已安装 Docker。当然你不必非得使用 Docker,但为了简单起见,强烈建议使用。运行起来之后,你需要执行数据库迁移并设置管理员用户。
### 数据库迁移
你需要先执行数据库迁移
```
docker compose exec api python manage.py migrate
```
你可以使用以下命令验证/查看迁移
```
docker compose exec api python manage.py showmigrations
```
用于开发:如果你想创建新的迁移,可以在对模型进行更改后运行以下命令。
```
docker compose exec api python manage.py makemigrations
```
### 使用 docker compose 运行
你可以通过以下命令启动整个技术栈
```
docker compose up
```
或者,你可以运行 watch 模式,这在开发过程中对于当代码发生更改时重启容器非常有用。
```
docker compose watch
```
### 使用应用
你可以访问此处的 React 前端:http://localhost:5173/
你会看到“你的项目”页面,该页面简单地列出了你上传的所有项目。你可以通过点击“View”来查看扫描摘要/安全发现。

_(“你的项目”页面截图)_
要上传新项目,只需点击右上角的“New Project”。这会跳转到一个上传表单,你可以在那里上传用于扫描的 ZIP 压缩包。

_(上传表单截图)_
扫描会在后台异步进行,因此你可以随意离开该页面去忙别的。扫描完成后,你将看到发现的问题、影响程度及其发现位置的详细分类。注意:行号是我目前仍需捕获的内容(参见待办事项/未来功能)。

_(扫描摘要页面截图)_
## 可观测性
我在 Grafana 中创建了几个简单的仪表板;一个用于 RabbitMQ 指标(运维),另一个用于安全威胁/洞察(发现的最常见漏洞等)。它们应该位于 `./monitoring/json` 目录下,并在启动时自动添加到 Grafana 中。

_(展示来自 prometheus 的 rabbitmq 指标的 Grafana 仪表板)_

_(展示安全数据的 Grafana 仪表板:发现的前 5 大漏洞及影响严重程度分布)_
## 调试
以下是在开发过程中用于调试的一些实用链接。
| 组件 | 链接 | 备注 |
| ------------- | ------------- | ------------- |
| 前端 | http://localhost:5173/login | React 前端。演示登录:`user:pass` |
| Grafana | http://localhost:3000/ | 包含 rabbitmq 指标和安全仪表板。登录凭据:`admin:pass` |
| Prometheus | http://localhost:9090/targets | 在 prometheus 中查询指标 - 对调试很有用 |
| RabbitMQ 管理界面 | http://localhost:15672 | 用于管理和查看队列、交换器等的 UI。登录凭据:`guest:guest` |
| Django 管理后台 | http://localhost:8000/admin | 可以显示/管理你选定模型的数据;ZIP 上传和扫描发现。登录凭据:`admin:pass` |
| Bucket 调试 | http://localhost:8000/debug | 返回 bucket 和其中条目 JSON 数据的 Django endpoint |
如果 bucket 调试 endpoint 帮不上忙,这里有一些有用的 garage(对象存储)命令。你也可以查看 garage 的帮助命令了解更多信息。
```
docker compose exec object-store /garage bucket list
docker compose exec object-store /garage bucket info pending-bucket
```
## 开发
如上所述,建议使用 `docker compose watch`。如果还没有的话,在继续之前你应该遵循上面“快速开始”中的前置条件。
如果你对 Dockerfile 进行了修改,你可能需要重新构建容器 `docker compose up --build`。
### 保存仪表板
在 Grafana 中创建仪表板时,它不会在容器停止/启动时持久化保存。为了持久化,你可以将仪表板导出为代码,并将其保存在本仓库的 `./monitoring/json` 目录下。
注意:有时如果你重启并尝试重新编辑仪表板,UI 会阻止你操作。如果发生这种情况,你可以直接从文件中进行编辑。或者你可以备份该文件然后重新导入。这并不理想,但我还没找到更简便的处理方法。
### Linter 与格式化
目前只有 Python API 配备了 linter/formatter。以下是一些帮助你入门的实用命令
```
# 识别 lint 问题但不应用修复
ruff check .
# 识别 lint 问题并应用修复
ruff check --fix .
# 根据设定的规则应用 formatting
ruff format .
```
Ruff 可以配置特定的规则,但我保留了默认设置,因为它们一开始看起来就很合理。
## 待办事项
在我转向处理 `未来新增功能/已知问题` 之前接下来的任务。
- 添加幂等性检查、唯一文件名 - 考虑使用 redis
- 为 pending bucket 添加生命周期策略以清理 ZIP 文件。同时将其移动到 processed bucket。
- 数据验证库?
- 捕获安全发现的行位置 - 目前它只能识别出检查是否存在于项目中以及它所在的文件
- 文件上传时,如果可能出现名称/UUID 冲突,则避免文件覆盖(考虑竞态条件)
- 改进错误处理,包括 DLQ 延迟重试
## 未来新增功能/已知问题
- 添加扫描项目的清理代码
- 用更健壮的解决方案替换 console.log(比如 pino logger?)
- 通过 tracing/correlation 等改进日志记录
- 添加代码片段视图 - 点击展开
- 添加误报/修复建议功能?
- 扩展 Semgrep 错误处理(Semgrep 会返回 errors 数组)
- 改进安全检查:
- 在安全沙箱而非 worker 中运行扫描 - 需要探索/研究此内容
- ZIP 路径遍历
- 符号链接隐患?
- 添加依赖项检查 - 识别存在问题的包,例如 package.json、requirements.txt 等
- 添加用于识别任何密钥的检查,例如 Gitleaks
- 扩展可观测性,例如将平均扫描时间添加到 Grafana
- 使安全发现/检查可配置 - 目前它们是硬编码的
## 实用资源/文档
* Django 风格指南/约定:https://github.com/HackSoftware/Django-Styleguide
* Django 中的 Outbox 模式:https://github.com/juntossomosmais/django-outbox-pattern
* 手动发布事件(区别于使用装饰器):https://github.com/juntossomosmais/django-outbox-pattern#publish-message-via-outbox
* Node RabbitMQ:https://www.rabbitmq.com/tutorials/tutorial-one-javascript
* 用于测试扫描器的实用项目:[DVWA](https://github.com/digininja/DVWA)、[WebGoat](https://owasp.org/www-project-webgoat/)、[NodeGoat](https://github.com/owasp/nodegoat)、[OWASP Juice Shop](https://owasp.org/www-project-juice-shop/)、[OWASP VulnerableApp](https://owasp.org/www-project-vulnerableapp/)。
标签:DevSecOps, Django, MITM代理, Python, Semgrep, WordPress安全扫描, 上游代理, 事件驱动, 无后门, 自定义请求头, 请求拦截, 逆向工具, 静态应用安全测试