Zaffri/sast-scanner

GitHub: Zaffri/sast-scanner

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

Stars: 0 | Forks: 0

# SAST Scanner ![](https://img.shields.io/badge/Python-3776AB?logo=python&logoColor=white) ![](https://img.shields.io/badge/Django-092E20?logo=django&logoColor=white) ![](https://img.shields.io/badge/Node.js-339933?logo=nodedotjs&logoColor=white) ![](https://img.shields.io/badge/RabbitMQ-FF6600?logo=rabbitmq&logoColor=white) ![](https://img.shields.io/badge/SQLite-003B57?logo=sqlite&logoColor=white) ![](https://img.shields.io/badge/Grafana_Loki-F46800?logo=grafana&logoColor=white) ![](https://img.shields.io/badge/Prometheus-E6522C?logo=prometheus&logoColor=white) ![](https://img.shields.io/badge/Amazon_S3-569A31?logo=amazons3&logoColor=white) 一个用于静态应用安全测试(SAST)的事件驱动 pipeline。旨在接收并自动扫描上传的代码库,以提供安全报告摘要。 ![展示 DVWA (Damn Vulnerable Web Application) 被上传并扫描的演示](https://static.pigsec.cn/wp-content/uploads/repos/cas/82/82c845e68b669852d59b5ee126a73023023ee29b86c380e4732b9b72d9b18ae3.gif) _(展示 DVWA (Damn Vulnerable Web Application) 被上传并扫描的演示)_ ## 功能 * 文件上传:用户可以 ZIP 格式上传他们的项目,并存储在类似 S3 的存储(Garage)中。 * 异步扫描任务:worker 从队列中提取待处理的扫描任务,并在后台按照自己的节奏进行扫描。 * 安全扫描:worker 解压项目并使用 Semgrep 来识别安全发现。 * 持久化与可观测性:安全发现存储在数据库中。Grafana 仪表板用于展示简单的运维指标和安全洞察。Prometheus 和 Loki 用于转发日志并向 Grafana 暴露指标。 * React 前端,用户可以登录、上传项目/代码库进行扫描并查看结果。 _注意:该项目仍在开发中。目前功能有限,请参阅下方的“未来新增功能/已知问题”标题。_ ## 系统设计与技术栈 _包含通用组件和系统设计的高层级架构图。_ ![系统设计图](https://static.pigsec.cn/wp-content/uploads/repos/cas/4a/4ab6a748f7fa3ef212b5d603aa1703ab7d8464c682cbbebb940a46a9f648e19b.svg) ### 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”来查看扫描摘要/安全发现。 ![“你的项目”页面截图](https://static.pigsec.cn/wp-content/uploads/repos/cas/8c/8ce40db109c67fc240150d9f5bcf8d2b0add4b84bc31ea57789313e162235536.png) _(“你的项目”页面截图)_ 要上传新项目,只需点击右上角的“New Project”。这会跳转到一个上传表单,你可以在那里上传用于扫描的 ZIP 压缩包。 ![上传表单截图](https://static.pigsec.cn/wp-content/uploads/repos/cas/cd/cd10d822fbb20b12f7c3ead39935ba7740071572e6a24fe67a07529324181f14.png) _(上传表单截图)_ 扫描会在后台异步进行,因此你可以随意离开该页面去忙别的。扫描完成后,你将看到发现的问题、影响程度及其发现位置的详细分类。注意:行号是我目前仍需捕获的内容(参见待办事项/未来功能)。 ![扫描摘要页面截图](https://static.pigsec.cn/wp-content/uploads/repos/cas/c2/c29290f3901951d451dcb712168908bc3d15f68ee19256ee14c46a0226625fc2.png) _(扫描摘要页面截图)_ ## 可观测性 我在 Grafana 中创建了几个简单的仪表板;一个用于 RabbitMQ 指标(运维),另一个用于安全威胁/洞察(发现的最常见漏洞等)。它们应该位于 `./monitoring/json` 目录下,并在启动时自动添加到 Grafana 中。 ![展示 rabbitmq 指标的 Grafana 仪表板](https://static.pigsec.cn/wp-content/uploads/repos/cas/7b/7ba6cf8692c807822606d8632a8d995d450f772d465e62b1f4b03f72ddc7b88a.png) _(展示来自 prometheus 的 rabbitmq 指标的 Grafana 仪表板)_ ![展示安全洞察的 Grafana 仪表板](https://static.pigsec.cn/wp-content/uploads/repos/cas/de/de305bf2483fc88c70fa45f34156af09f313f6646f7b2147379b42f732423b06.png) _(展示安全数据的 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安全扫描, 上游代理, 事件驱动, 无后门, 自定义请求头, 请求拦截, 逆向工具, 静态应用安全测试