silvatechf/AppSec-Scanner
GitHub: silvatechf/AppSec-Scanner
一款 Python 静态分析安全扫描引擎,提供漏洞检测、安全自动修复决策、结构化审计追踪和 CI/CD 安全门禁能力。
Stars: 0 | Forks: 0
# AppSec Scanner — Python 漏洞检测、修复与审计
静态分析引擎(AST)用于检测 Python 代码中的漏洞类别,
通过**明确的标准**决定哪些漏洞可以无风险地自动修复,
并留下结构化的审计跟踪,以备可观测性(Loki/Grafana)使用,
并充当 CI/CD 中的安全门禁。
它不仅仅是一个代码检查工具。它是大多数个人扫描器缺失的关键部分:
**关于检测和修复确实已发生的可审计证据**,
这正是合规团队(SOC 2、ISO 27001)或高级技术审查员所要求的。
## 为什么存在
大多数作品集中的安全项目都停留在“我检测到了漏洞”。这仅仅是 20% 的问题。剩下的 80% —— 也是在实际团队中真正重要的部分 —— 是:
1. 哪些可以**在不破坏任何东西的情况下**自动修复,哪些不能?
2. 如何留下关于该决定的证据,且可供第三方验证?
3. 如何将其集成到 pipeline 中,以至于没人需要记住去运行它?
这个项目用实际运行的代码回答了这三个问题,而不是用幻灯片。
## 目前检测的内容
| 规则 | 检测目标 | 是否自动修复? |
|---|---|---|
| `sql_injection` | 使用 f-string、字符串拼接或 `%`-format 构建的 SQL | 仅限 `%`-format 情况 —— 这是在不执行代码的情况下,唯一被证明是安全的 |
| `path_traversal` | `open()`、`os.remove()`、`os.unlink()`、`os.rmdir()`、`shutil.rmtree()` 中的动态路径 | 否 —— 在不知道每个上下文允许的基础目录的情况下,不存在安全的通用重写方式 |
其架构专为扩展而设计:每条规则都实现了一个通用的 `Rule` 接口,因此添加第三类漏洞完全不会触及引擎的其他部分。
## 真实执行证据(非模拟)
这是对自身的测试语料库运行引擎的真实输出:
```
$ python appsec_scanner/scanner.py benchmark/cases --audit-log tests/demo_audit.jsonl
AppSec scan: 5 hallazgo(s) totales
```
对唯一安全情况(`%`-format → 参数化查询)的自动修复:
```
- query = "SELECT * FROM orders WHERE id = %s" % order_id
+ query = "SELECT * FROM orders WHERE id = ?", (order_id,)
```
当存在未修复的 `CRITICAL` 发现时,CI 门禁正确拦截:
```
$ python appsec_scanner/scanner.py benchmark/cases --fail-on-critical
AppSec gate: 4 hallazgo(s) CRITICAL sin remediar
$ echo $?
1
```
针对标记语料库的 Benchmark:
```
TP=5 FP=0 FN=0 TN=5
Precisión: 1.00 Recall: 1.00 F1: 1.00
sql_injection: {'tp': 3, 'fp': 0, 'fn': 0, 'tn': 2}
path_traversal: {'tp': 2, 'fp': 0, 'fn': 0, 'tn': 2}
```
**特此以粗体诚实声明:** 此 benchmark 是由作者自行构建的 10 个测试用例的语料库,而非官方的 OWASP Benchmark(该项目用于评估 Java/JVM,不适用于 Python 扫描器)。在由引擎作者自行构建的 10 个用例上取得的 1.00 F1 分数,仅验证了逻辑按设计运行 —— 这并不能保证能推广到真实的生产代码中。关于此局限性的完整细节,以及被刻意排除在范围之外的内容,详见 [`docs/modelo_de_amenazas.md`](docs/modelo_de_amenazas.md)。
## 如何运行
```
# 在不修改任何内容的情况下检测
python appsec_scanner/scanner.py --audit-log tests/security_audit.jsonl
# 检测并自动修复可以安全修复的内容
python appsec_scanner/scanner.py --fix
# 将其用作 CI gate(如果存在未修复的 CRITICAL,则以代码 1 退出)
python appsec_scanner/scanner.py --fail-on-critical
# 验证引擎指标
python benchmark/run_benchmark.py
```
为 GitHub Actions 准备好的集成位于 [`ci/appsec-gate.yml`](ci/appsec-gate.yml):
它运行扫描,如果有未解决的关键漏洞则阻止 PR,运行 benchmark,并将审计日志发布为可下载的 artifact。
## 如何启动 observability stack(已在本地测试)
```
cd infra
docker compose up -d
docker compose ps # confirma que loki, promtail y grafana estén "Up"
cd ..
python appsec_scanner/scanner.py benchmark/cases --audit-log tests/security_audit.jsonl --fix
```
打开 `http://localhost:3000`(用户名/密码:`admin`/`admin`) →
**Connections → Data sources → Add data source → Loki** → URL `http://loki:3100`
→ **Save & test**。然后 **Dashboards → Import** → 上传
`grafana/grafana_dashboard.json` 并选择数据源 `loki`。
## Observability
事件以 JSONL(`event_type`、`severity`、`details`、`timestamp`)格式写入,
该格式专为 Promtail → Loki → Grafana 设计。完整的基础设施位于
[`infra/`](infra/)(包含 Loki + Promtail + Grafana 的 `docker-compose.yml`),
可导入的 dashboard 在 [`grafana/grafana_dashboard.json`](grafana/grafana_dashboard.json)。
**该 stack 已经在本地搭建并运行过,绝非仅仅是理论配置。**
该 dashboard 包含 7 个面板,其中展示了由引擎自身生成的真实数据:
- **总发现数 / 受影响文件 / 活动规则** — 带有 sparkline 的统计数据
- **按类型划分的事件** — `REMEDIATION_SUCCESS` 对比
`REMEDIATION_FAILURE` 的时间序列(柱状图),按严重程度着色
- **按严重程度分布** — 具有正确阈值的饼图
(严重显示为红色,而不是绿色 —— 这正是我们在构建过程中发现并修复的 bug 之一)
- **修复成功率** — 带有阈值的仪表盘(红色 <50%,绿色 >80%)
- **最近的关键事件** — 简洁的表格,没有原始 JSON,严重程度以单元格背景色表示
要生成真实的历史记录(非伪造的 timestamp),并查看包含多个数据点而非单一峰值的时间序列,请使用
[`infra/seed_history.py`](infra/seed_history.py):在每次执行之间设置真实的停顿,多次运行 scanner。
每个面板的精确配置(LogQL 查询、可视化类型、颜色覆盖、transforms)均记录在
[`docs/ficha_paneles_grafana.md`](docs/ficha_paneles_grafana.md) 中,以防您需要从零开始重建 dashboard。
**诚实声明:** 在构建此 dashboard 的过程中,我们发现并修复了几个实际存在的错误 —— 其中一个查询的错误标签引用导致成功率面板出现 "No data";一个 "Top 文件" 面板被错误地配置为 Bar gauge 而不是 Bar chart;以及一个编码问题(PowerShell 的 BOM),导致 scanner 静默丢弃了语料库中的一个文件。我们将整个过程记录下来,而不是仅仅展示最终结果,因为诊断和修复这些错误的标准本身就是本项目技术证据的一部分。
## 仓库结构
```
appsec_scanner/scanner.py # motor: interfaz Rule + AuditLogger + CLI
benchmark/ # corpus etiquetado + cálculo de precisión/recall/F1
ci/appsec-gate.yml # workflow de GitHub Actions como gate real
infra/docker-compose.yml # Loki + Promtail + Grafana, listo para docker compose up
infra/seed_history.py # genera historial real (timestamps genuinos) para el dashboard
grafana/grafana_dashboard.json # dashboard importable con 7 paneles
docs/modelo_de_amenazas.md # alcance, exclusiones justificadas, límites metodológicos
docs/ficha_paneles_grafana.md # queries y configuración exacta de cada panel
```
## 本项目“不是”什么
为了像明确它能做什么一样,明确它不能做什么:这不能替代 pentest,它不涵盖 ORM(因为 ORM 在设计上已经进行了参数化),它不追踪通过 `eval`/`exec` 组装的 SQL,并且它不会自动修复 path traversal,因为不存在安全的通用规则可以做到这一点。每一项排除都在威胁模型中给出了正当理由,并非出于疏忽而被遗漏。
## 已知待办事项(坦诚说明,尚未解决)
- **MTTR(平均修复时间):** 使用当前的日志 schema 无法计算,
因为每个事件都是独立的,并且在同一发现的“检测”和“修复”之间不存在关联 ID。这需要修改 `AuditLogger` 以发出一对相关联的事件。
- **Grafana 告警:** 面板已经准备好进行配置(Alert 选项卡),但在能够向某处发送通知之前,还需要定义一个 Contact point
(Slack/电子邮件)。
- **扩展的 Benchmark:** 当前的指标是基于自行构建的 10 个用例,
而非真实的第三方生产代码(详见 `docs/modelo_de_amenazas.md` 中的明确限制)。
## 安全标准 🔐
本仓库遵循严格的安全规范,以确保软件供应链完整性(*Software Supply Chain Integrity*):
* **GPG Signing:** 所有 *commits* 均通过 GPG 密钥进行数字签名,以保证作者身份的真实性。
* **Automated Security Headers:** 源代码文件包含通过 Git hooks(`pre-commit`)自动注入的作者信息标头,以确保标准化和可追溯性。
* **Git Integrity:** 采用严格的 `.gitignore` 文件,防止意外泄露密钥、日志(*logs*)或敏感数据。
## 为什么存在
大多数作品集中的安全项目都停留在“我检测到了漏洞”。这仅仅是 20% 的问题。剩下的 80% —— 也是在实际团队中真正重要的部分 —— 是:
1. 哪些可以**在不破坏任何东西的情况下**自动修复,哪些不能?
2. 如何留下关于该决定的证据,且可供第三方验证?
3. 如何将其集成到 pipeline 中,以至于没人需要记住去运行它?
这个项目用实际运行的代码回答了这三个问题,而不是用幻灯片。
## 目前检测的内容
| 规则 | 检测目标 | 是否自动修复? |
|---|---|---|
| `sql_injection` | 使用 f-string、字符串拼接或 `%`-format 构建的 SQL | 仅限 `%`-format 情况 —— 这是在不执行代码的情况下,唯一被证明是安全的 |
| `path_traversal` | `open()`、`os.remove()`、`os.unlink()`、`os.rmdir()`、`shutil.rmtree()` 中的动态路径 | 否 —— 在不知道每个上下文允许的基础目录的情况下,不存在安全的通用重写方式 |
其架构专为扩展而设计:每条规则都实现了一个通用的 `Rule` 接口,因此添加第三类漏洞完全不会触及引擎的其他部分。
## 真实执行证据(非模拟)
这是对自身的测试语料库运行引擎的真实输出:
```
$ python appsec_scanner/scanner.py benchmark/cases --audit-log tests/demo_audit.jsonl
AppSec scan: 5 hallazgo(s) totales
```
对唯一安全情况(`%`-format → 参数化查询)的自动修复:
```
- query = "SELECT * FROM orders WHERE id = %s" % order_id
+ query = "SELECT * FROM orders WHERE id = ?", (order_id,)
```
当存在未修复的 `CRITICAL` 发现时,CI 门禁正确拦截:
```
$ python appsec_scanner/scanner.py benchmark/cases --fail-on-critical
AppSec gate: 4 hallazgo(s) CRITICAL sin remediar
$ echo $?
1
```
针对标记语料库的 Benchmark:
```
TP=5 FP=0 FN=0 TN=5
Precisión: 1.00 Recall: 1.00 F1: 1.00
sql_injection: {'tp': 3, 'fp': 0, 'fn': 0, 'tn': 2}
path_traversal: {'tp': 2, 'fp': 0, 'fn': 0, 'tn': 2}
```
**特此以粗体诚实声明:** 此 benchmark 是由作者自行构建的 10 个测试用例的语料库,而非官方的 OWASP Benchmark(该项目用于评估 Java/JVM,不适用于 Python 扫描器)。在由引擎作者自行构建的 10 个用例上取得的 1.00 F1 分数,仅验证了逻辑按设计运行 —— 这并不能保证能推广到真实的生产代码中。关于此局限性的完整细节,以及被刻意排除在范围之外的内容,详见 [`docs/modelo_de_amenazas.md`](docs/modelo_de_amenazas.md)。
## 如何运行
```
# 在不修改任何内容的情况下检测
python appsec_scanner/scanner.py 标签:DevSecOps, Python, 上游代理, 代码安全审计, 无后门, 模块化设计, 自动化修复, 请求拦截, 逆向工具, 错误基检测, 静态代码分析