NikaNats/Sentinel
GitHub: NikaNats/Sentinel
Sentinel是一款基于.NET 10的零信任API安全框架。
Stars: 0 | Forks: 0
# 哨兵
Sentinel 是一个以安全为重点的 ASP.NET Core Web API,它强制执行与 FAPI 2.0 基线和高级强化目标一致的发送者约束令牌验证模式。
当前实现提供:
- DPoP 访问令牌处理,包括证明验证和nonce发行
- 支持Redis的访问令牌jti和DPoP证明jti的重放检测
- ACR和基于作用域的授权要求
- 对cnf.x5t#S256绑定的令牌进行mTLS证书绑定检查
- 严格的JWT算法约束和零时钟偏移生存期验证
- 安全遥测、安全头、速率限制和结构化错误处理
## 规范和交付工件
- 规范:[SPEC-0001 - 用户身份验证和令牌发行](./.specify/specs/SPEC-0001-auth-token-issuance.md)
- 实施计划:[PLAN-0001 - 身份验证实施](./.specify/plans/PLAN-0001-auth-implementation.md)
- 任务分解:[TASK-0001 - 身份验证实施任务](./.specify/tasks/TASK-0001-auth-implementation.md)
## 综合文档套件
**适用于所有受众的生产级文档。** 从[文档索引](./docs/README.md)开始。
| 文档 | 受众 | 目的 |
|----------|----------|---------|
| [ARCHITECTURE.md](./docs/ARCHITECTURE.md) | 架构师、工程师 | 10个架构决策记录(ADRs)解释DPoP、重放缓存、速率限制、nonce管理、中间件排序、幂等性和运营设计 |
| [SDK_LESS_INTEGRATION_GUIDE.md](./docs/SDK_LESS_INTEGRATION_GUIDE.md) | 客户端开发者 | 完整的HTTP/REST集成指南,包括5种语言(JS、Python、Java、C#、Go)的DPoP证明生成和完整的端到端示例 |
| [LIVING_THREAT_MODEL.md](./docs/LIVING_THREAT_MODEL.md) | 安全团队、审计员 | 7个类别中21个已识别的威胁,包括缓解分析、可能性×影响矩阵和剩余风险评估 |
| [SRE_SOC_RUNBOOKS.md](./docs/SRE_SOC_RUNBOOKS.md) | SRE、SOC、值班 | 监控、警报、事件响应程序、故障排除指南和维护清单,包括bash/PowerShell命令 |
| [COMPLIANCE_AUDIT_MATRIX.md](./docs/COMPLIANCE_AUDIT_MATRIX.md) | 合规性、审计员 | 合规性框架映射(OAuth 2.0、JWT、DPoP RFC 9449、FAPI 2.0 基线)以及40多个审计清单项 |
| [OPENAPI_3_1.yaml](./docs/OPENAPI_3_1.yaml) | API消费者 | 正式的OpenAPI 3.1规范;用于SDK生成和API网关集成的机器可读API合同 |
| [BUILD_CONFIGURATION_GUIDE.md](./docs/BUILD_CONFIGURATION_GUIDE.md) | 开发者、DevOps | Directory.Build.props解释、构建工作流、代码分析策略、AOT/可重用性以及故障排除 |
**按角色快速入门:**
- **客户端开发者:** 从[SDK_LESS_INTEGRATION_GUIDE.md](./docs/SDK_LESS_INTEGRATION_GUIDE.md)和[OPENAPI_3_1.yaml](./docs/OPENAPI_3_1.yaml)开始
- **SRE / 运营:** 从[SRE_SOC_RUNBOOKS.md](./docs/SRE_SOC_RUNBOOKS.md)开始
- **安全 / 合规性:** 从[LIVING_THREAT_MODEL.md](./docs/LIVING_THREAT_MODEL.md)和[COMPLIANCE_AUDIT_MATRIX.md](./docs/COMPLIANCE_AUDIT_MATRIX.md)开始
- **架构师 / 首席工程师:** 从[ARCHITECTURE.md](./docs/ARCHITECTURE.md)开始
- **开发者 / DevOps:** 从[BUILD_CONFIGURATION_GUIDE.md](./docs/BUILD_CONFIGURATION_GUIDE.md)开始
## 实施状态
| 区域 | 状态 | 备注 |
|---|---|---|
| API主机和中间件管道 | 实现 | 安全中间件链和集中异常处理是活动的 |
| JWT验证和策略授权 | 实现 | 发行者、受众、生存期、算法验证、ACR和作用域强制执行 |
| DPoP证明验证 | 实现 | htm、htu、iat窗口、typ、alg、jwk、cnf.jkt检查;符合RFC 9449的nonce挑战-响应 |
| 重放保护 | 实现 | 原子Redis支持的jti缓存(SET NX),失败关闭行为,60秒TTL与令牌生存期对齐 |
| DPoP nonce管理 | 实现 | 每个JWK指纹旋转nonce;原子比较-删除事务防止消费竞争;在陈旧/已消费不匹配时挑战发行新鲜nonce |
| mTLS令牌绑定 | 实现 | cnf.x5t#S256与提供的客户端证书哈希值比较;可选的第二因素 |
| 速率限制 | 实现 | 双分区链式强制执行:身份分区(sub+client_id或匿名时的per-IP)和始终存在的IP分区;429响应包括Retry-After头 |
| 幂等性强制执行 | 实现 | 注销幂等性具有状态机(IN_PROGRESS→409,COMPLETED→204) |
| 会话管理 | 实现 | 刷新令牌轮换;注销时会话黑名单;TTL与Keycloak(默认8小时)对齐 |
| OpenTelemetry和度量端点 | 实现 | 跟踪、度量计数器/直方图、Prometheus抓取端点;安全事件遥测 |
| 集成和单元测试 | 实现 | 50/50测试通过,具有完整的场景覆盖 |
| 全OAuth PAR和PKCE编排端点集 | 计划/外部化 | Keycloak驱动的流程编排仍然是基础设施和客户端驱动的 |
## 架构概述
### 运行时管道
API管道以防御深度序列应用控制:
1. 全局异常处理和问题详情格式化
2. 安全响应头强化(HSTS、CSP、frame-deny、no-sniff、cache-control)
3. 全局固定窗口速率限制器(per-identity + per-IP双分区)
4. JWT身份验证(发行者、受众、生存期、算法验证)
5. 速率限制器评估(两个分区都必须有可用配额)
6. DPoP验证中间件(证明结构、签名、htm/htu绑定、nonce验证)
7. mTLS证书绑定中间件(可选cnf.x5t#S256验证)
8. ACR存在验证中间件
9. 授权策略强制执行(作用域、每个端点的ACR要求)
10. 控制器端点执行
11. 响应头(DPoP-Nonce用于下一个请求轮换)
12. Prometheus抓取端点(/metrics)
### 核心安全组件
- **DPoP验证器**强制执行RFC 9449合规性:验证证明签名、类型、算法、htm/htu绑定、iat新鲜度(±60秒)、jti证明重放通过原子Redis缓存、以及每个指纹的nonce消费
- **重放缓存**存储JWT jti和证明jti,使用原子SET NX(When.NotExists)语义;Redis不可用时返回503失败关闭
- **nonce存储**管理每个JWK指纹旋转nonce;原子比较-删除事务防止消费竞争;在陈旧/已消费不匹配时挑战发行新鲜nonce
- **速率限制器**实现双分区链式强制执行:身份分区(sub+client_id或匿名时的per-IP)和始终存在的IP分区;429响应包括Retry-After头
- **安全事件发射器**生成具有关联ID的结构化OpenTelemetry Activity事件,用于SIEM切换
- **ACR和作用域授权处理程序**在端点级别使用声明验证应用细粒度策略检查
## 仓库布局
```
Sentinel/
|- Sentinel.slnx
|- Directory.Build.props ← Centralized build config (all projects inherit)
|- docker-compose.yml
|- Makefile
|- docs/
| |- README.md ← Documentation index
| |- ARCHITECTURE.md ← ADRs (10 decisions)
| |- SDK_LESS_INTEGRATION_GUIDE.md ← Client integration (5 languages)
| |- LIVING_THREAT_MODEL.md ← Security threat analysis (21 threats)
| |- SRE_SOC_RUNBOOKS.md ← Operational procedures
| |- COMPLIANCE_AUDIT_MATRIX.md ← Regulatory framework mapping
| |- OPENAPI_3_1.yaml ← API specification (OpenAPI)
| |- BUILD_CONFIGURATION_GUIDE.md ← Build config explanation & workflow
|- artifacts/ ← Centralized build output (bin/obj)
| |- bin/
| |- obj/
|- infra/
| |- keycloak/
| |- realms/
| |- sentinel.json
|- .github/
| |- workflows/
| |- agents/
| |- prompts/
|- .specify/
| |- specs/
| |- plans/
| |- tasks/
|- src/
| |- Sentinel.Domain/
| |- Sentinel.Application/
| |- Sentinel.Infrastructure/
| |- Sentinel.AspNetCore/
|- tests/
| |- Sentinel.Tests/
| |- Integration/
| |- Unit/
|- artifacts/ ← Build output (bin/obj centralized)
```
## 技术堆栈
| 组件 | 版本 | 用途 |
|---|---|---|
| .NET SDK | 11.0 preview | 构建 和 运行时 |
| ASP.NET Core | 11.0 preview packages | API框架和中间件 |
| Keycloak | 26.1 image in compose | 授权服务器和领域管理 |
| Redis | 7.4 alpine | 重放缓存后端存储 |
| OpenTelemetry | 1.13 to 1.14 packages | 跟踪、度量、导出器集成 |
| xUnit + Testcontainers | 当前项目引用 | 单元和集成验证 |
## 先决条件
- Windows、Linux或macOS开发环境
- 安装.NET 11 SDK预览版
- Docker Desktop或Docker Engine
- 可选:Trivy进行镜像漏洞扫描
## 构建配置
**Directory.Build.props**为所有项目提供集中配置:
| 功能 | 设置 | 目的 |
|---------|---------|---------|
| **工件布局** | `UseArtifactsOutput: true` | 中心化的bin/obj → artifacts/文件夹(无树污染) |
| **框架** | `TargetFramework: net11.0` | .NET 11预览(最新) |
| **代码分析** | `AnalysisLevel: latest-all` | 严格的代码质量检查(尽早捕捉问题) |
| **警告作为错误** | 发布/CI仅限 | 零警告策略;在CI阶段强制执行 |
| **AOT兼容性** | 可用于可执行文件 | 本地AOT就绪;修剪安全的代码分析 |
| **安全** | NuGetAudit、ControlFlowGuard | 阻止易受攻击的包;启用控制流保护 |
| **可重用构建** | `Deterministic: true` | 开发机二进制文件 = CI二进制文件(无差异) |
| **语言** | `Nullable: enable`、`ImplicitUsings: enable` | 现代C#,具有严格的空安全 |
| **锁文件** | `RestorePackagesWithLockFile: true` | 冻结的传递依赖关系以实现可重用性 |
所有项目自动继承这些设置;仅在必要时在单个.csproj中进行覆盖。
## 快速入门
交互式API参考(仅限开发):
http://localhost:5260/scalar
### 1. 还原、构建、测试
```
dotnet restore Sentinel.slnx --locked-mode
dotnet build Sentinel.slnx -c Release
dotnet test Sentinel.slnx
```
### 2. 使用Docker Compose启动本地基础设施和API
```
docker-compose up --build -d
```
服务:
- Keycloak:https://localhost:8443 和 http://localhost:8080
- Redis:localhost:6379
- Sentinel API:http://localhost:5260
### 3. 直接运行API(不使用Compose)
```
cd src/Sentinel.AspNetCore
dotnet run
```
### 4. 停止本地堆栈
```
docker-compose down -v
```
## 强名称签名(混合模型)
Sentinel强制对所有程序集执行强名称签名。本地开发使用`PublicSign`与`Sentinel.public.snk`(已提交到源代码控制)当私有密钥不可用或在不支持Windows的系统上构建时,而CI/CD发布构建执行完整的签名,通过注入通过机密注入的私有密钥。
为了防止在积极本地开发期间`InternalsVisibleTo`与未签名的测试项目之间的加密冲突,仅在官方发布打包期间条件性地启用程序集签名。
### 生成强名称密钥(本地安全管理员)
```
sn -k Sentinel.snk
```
### 提取公钥(用于PublicSign场景)
```
sn -p Sentinel.snk Sentinel.public.snk
```
### 使用强名称签名编译和打包
要构建和打包带有强名称签名的生产NuGet库,请传递SignSentinelRelease=true属性:
```
dotnet pack Sentinel.slnx -c Release -p:SignSentinelRelease=true -o ./artifacts
```
### CI/CD安全签名(GitHub Actions)
1. 将base64编码的Sentinel.snk存储在GitHub Secrets中(例如 SENTINEL_SNK_BASE64)。
2. 在.github/workflows/security-pipeline.yml中,在构建之前将机密解码到工作区:
```
- name: Restore strong-name key (Staging/Release Only)
if: ${{ secrets.SENTINEL_SNK_BASE64 != '' }}
shell: bash
run: echo "$SENTINEL_SNK_BASE64" | base64 -d > Sentinel.snk
env:
SENTINEL_SNK_BASE64: ${{ secrets.SENTINEL_SNK_BASE64 }}
```
这使私有密钥不在源代码控制中,同时确保发布构建得到完全签名。
## Make目标
```
make build # locked restore + release build
make test # run all tests
make mutation # run mutation tests for DPoP-critical paths
make lint # dotnet format verification
make sec-scan # build image + trivy scan (critical/high)
make up # docker-compose up --build -d
make down # docker-compose down -v
make all # build + lint + test + sec-scan
```
## 变异测试(安全网关)
变异测试通过Stryker.NET配置为DPoP关键代码路径:
```
dotnet tool restore
dotnet stryker --config-file stryker-config.json
```
基线网关阈值:
- break: 70
- low: 70
- high: 85
## 配置参考
所需的最小密钥:
| 密钥 | 目的 | 示例 |
|---|---|---|
| ConnectionStrings:Redis | 重放缓存后端 | localhost:6379 |
| Keycloak:Authority | 令牌发行者权威 | https://localhost:8443/realms/sentinel |
| Keycloak:Audience | 期望的访问令牌受众 | sentinel-api |
| Keycloak:RequireHttpsMetadata | Dev元数据通过HTTP切换 | false(仅限开发) |
| FeatureFlags:Auth:DpopFlow | 功能切换占位符 | true |
注意:
- 生产部署应保留HTTPS元数据要求。
- Redis可用性是安全边界的一部分;当Redis不可用时,服务降级为失败关闭(返回503服务不可用),阻止所有受保护资源访问,直到Redis恢复。
## API表面
### 受保护端点
- GET /v1/Profile
要求:
- 通过带有DPoP方案的Authorization头传递经过身份验证的JWT
- DPoP头中的匹配DPoP证明
- 满足策略ReadProfile:
- 作用域包括profile
- acr声明符合最小acr2
示例响应模型:
```
{
"sub": "subject-id",
"displayName": "display name",
"roles": ["user"]
}
```
## 安全控制
实现了RFC 9449(DPoP)+ FAPI 2.0基线强化控制:
**JWT验证:**
- 发行者和受众是必需的;与Keycloak领域配置进行验证
- 生存期是必需的,具有零时钟偏移容差
- 签名令牌是必需的;算法白名单限制为ES256、RS256、PS256
- JTI(JWT ID)重放检测:存储在Redis缓存,TTL与令牌生存期匹配(60秒)
- 重复JTI拒绝:返回503服务不可用(失败关闭)
**DPoP证明验证(RFC 9449):**
- 令牌和证明格式验证
- 类型必须是`dpop+jwt`;算法限制为ES256、RS256、PS256
- 内嵌的公共JWK是必需的;拒绝私钥材料
- 签名与内嵌的JWK进行验证
- `htm`(HTTP方法)和`htu`(HTTP URI)绑定强制执行并与请求进行比较
- `iat`新鲜度窗口强制执行(±60秒时钟偏移容差)
- 访问令牌`cnf.jkt`必须与证明JWK指纹匹配(S256)
- 证明JTI重放通过原子Redis SET NX(When.NotExists)缓存阻止
- 证明声明中必需每个JWK指纹的nonce
- 通过Redis事务比较-删除原子消费nonce(防止重用)
**nonce挑战-响应(RFC 9449 §4.3):**
- 服务器发行的nonce包含在`DPoP-Nonce`响应头中
- nonce与客户端的JWK指纹绑定;每个身份的nonce序列
- nonce生存期:60秒;过期触发挑战重新发行
- 初始未经过身份验证的请求返回400 Bad Request + nonce挑战
- 客户端在下一个证明中包含nonce;服务器在消费之前进行验证
- 陈旧/已消费nonce触发新的挑战发行,带有新鲜nonce
- 客户端必须从每个响应头中更新缓存的nonce
**访问令牌重放防御:**
- JTI声明是必需的并强制执行
- 在令牌生存期内(60秒)重复JTI被拒绝
- Redis故障触发失败关闭行为(503服务不可用)
**mTLS发送者约束(可选):**
- `cnf.x5t#S256`与提供的客户端证书SHA-256哈希值进行比较
- 启用可选的第二因素绑定(mTLS + DPoP)
**速率限制:**
- 双分区链式强制执行:
- **身份分区**:如果经过身份验证则为`{sub}:{client_id}`;如果匿名则为`{remote_ip}`
- **IP分区**:始终`{remote_ip}`(分层防御)
- 两个分区都必须有可用配额;如果任一耗尽则返回429 Too Many Requests
- 每个身份配额:10-20 req/min(可配置;身份验证端点较低)
- 每个IP配额:100 req/min(可配置;匿名隔离)
- 逐步降级:429响应包括`Retry-After`头
**会话管理:**
- 刷新令牌轮换在每次刷新时强制执行
- 检测到刷新令牌重用;第二次使用触发会话黑名单并强制重新身份验证
- 注销时进行会话黑名单;TTL与Keycloak `SsoSessionMaxLifespanSeconds`(默认8小时)对齐
- 注销时强制执行幂等性:需要`Idempotency-Key`头
- 幂等性状态机:IN_PROGRESS(409)与COMPLETED(204)的区别
- 支持后端通道注销(Keycloak发起的会话终止)
**HTTP响应强化:**
- HSTS(HTTP Strict-Transport-Security):最大1年max-age
- CSP(Content-Security-Policy):限制内联脚本、外部资源
- X-Content-Type-Options:nosniff(防止MIME类型嗅探)
- X-Frame-Options:DENY(防止点击劫持)
- X-XSS-Protection:1;mode=block(浏览器XSS过滤器)
- Referrer-Policy:strict-origin-when-cross-origin
- Permissions-Policy:限制API功能
- Cache-Control:no-store,must-revalidate(防止缓存敏感响应)
- 删除服务器和X
标签:API安全, DPoP, FAPI 2.0, JSON输出, JWT算法, ML-DSA签名, .NET开发, SD-JWT, Streamlit, 多人体追踪, 多因素认证, 威胁模型, 安全文档, 安全策略, 安全运营, 实时信号, 开发者指南, 扫描框架, 提示词设计, 搜索引擎查询, 架构设计, 用户代理, 访问控制, 证书绑定, 量子安全, 错误处理, 零信任安全