mano8/security-tests-m8
GitHub: mano8/security-tests-m8
面向 FastAPI M8 微服务堆栈的可复用实时安全测试套件,以 pytest 插件与 CLI 双模式验证认证、授权、JWT、速率限制等 API 安全机制在真实运行环境中的有效性。
Stars: 2 | Forks: 0
# security-tests-m8

[](https://pypi.org/project/security-tests-m8/)
[](https://pypi.org/project/security-tests-m8/)
[](https://pepy.tech/projects/security-tests-m8)
[](https://app.codacy.com/gh/mano8/security-tests-m8/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[](https://codecov.io/gh/mano8/security-tests-m8)
[](https://github.com/mano8/security-tests-m8/blob/main/LICENSE)
用于 FastAPI M8 认证和服务堆栈的可重用实时安全测试。
## 目录
- [摘要](#summary)
- [环境要求](#requirements)
- [安装](#install)
- [快速开始:CLI](#quick-start-cli)
- [破坏性与非破坏性测试](#destructive-vs-non-destructive-tests)
- [快速开始:pytest](#quick-start-pytest)
- [工作原理](#how-it-works)
- [配置](#configuration)
- [环境变量](#environment-variables)
- [选择 Env 文件](#choosing-an-env-file)
- [部署环境预检](#deployment-env-preflight)
- [CLI 与 pytest 模式](#cli-vs-pytest-mode)
- [单服务用法](#single-service-usage)
- [多服务用法](#multi-service-usage)
- [可用测试套件](#available-suites)
- [完整的认证服务示例](#full-auth-service-example)
- [Pytest 标记](#pytest-markers)
- [暴露的 Fixtures](#exposed-fixtures)
- [实时堆栈注意事项](#notes-for-live-stacks)
- [开发](#development)
- [示例](#examples)
## 摘要
`security-tests-m8` 是一个 pytest 插件,同时包含一组可重用的测试套件类。它允许任何 FastAPI M8 项目运行最初为 `fa-auth-m8` 编写的相同实时安全检查,而无需在不同仓库之间复制测试文件。
它针对 **任何 issuer 为 `fa-auth-m8` 且下游服务基于 `fastapi-m8` 构建的 Docker Compose(或远程)堆栈** —— 而不仅仅是加固的参考堆栈。`hardened_m8` 部署只是贯穿本 README 使用的示例;只需更改配置,即可将相同的套件指向最小化、预发布或生产堆栈。该插件会在收集阶段探测实时堆栈,并自动跳过不适用于检测到的算法、token 模式或可用组件的检查(参见 [工作原理](#how-it-works))。
使用它来测试:
- JWT 结构和 token 伪造保护
- RS256、ES256 和 HS256 算法行为
- 无状态、有状态和混合 token 模式
- 登录滥用、授权、IDOR、CORS、cookies、headers、metrics、健康检查、私有 API、头像、API keys 和速率限制
- 一个或多个下游 FastAPI M8 服务中的受保护 endpoint
这些测试针对真实的实时堆栈运行。它们不会 mock 你的认证服务。你只需将该包指向你正在运行的认证 URL、管理员凭据和可选的服务 URL,然后在你自己的测试文件中继承所需的套件类即可。
## 环境要求
- Python 3.11 或更高版本
- `pytest`
- 正在运行的 FastAPI M8 认证堆栈
- 一个可以通过 `/login/access-token` 登录的专用纯测试超级用户
- 用于受保护 endpoint 测试的可选下游 FastAPI M8 服务 URL
## 安装
从本仓库安装:
```
pip install -e .
```
从其他项目安装(或更新到最新版本),在测试环境中安装该包:
```
pip install --upgrade security-tests-m8
```
该包通过 `pytest11` 入口点将自己注册为 pytest 插件,因此安装后会自动提供 fixtures 和标记。
## 快速开始:CLI
对于常规的堆栈验证,请为测试运行器创建一个专用的实时测试 env 文件。在诸如 `/workspace/fa-auth-m8/examples/docker_compose/hardened_m8` 的堆栈目录下,创建一个包含 `LIVE_TEST_*` 值的 `test.env` 文件,替换掉所有的占位符密钥值,然后运行:
```
security-tests-m8 preflight --deployment-root .
security-tests-m8 run --env-file test.env
```
`security-tests-m8 run` 在内部保留 pytest 作为执行引擎,但它会为你创建临时的包测试模块。默认情况下,它运行 `-m "live and not destructive"`,这样重复的 CLI 运行就不会有意改变登录锁定、会话或速率限制状态。你仍然可以在 `--` 之后传递 pytest 选择标志:
```
security-tests-m8 run --env-file test.env -- -ra
security-tests-m8 run --env-file test.env --include-destructive
security-tests-m8 run --env-file test.env -- -m live_asymmetric -ra
```
常用命令:
```
security-tests-m8 run
security-tests-m8 run --env-file test.env
security-tests-m8 preflight
security-tests-m8 preflight --deployment-root .
security-tests-m8 scan-env --deployment-root .
security-tests-m8 list-suites
```
## 破坏性与非破坏性测试
非破坏性测试设计为对于重复的常规验证运行是安全的。它们读取实时 endpoint,检查 token 结构,验证访问控制,检查 headers/cookies,并避免有意消耗锁定或撤销状态。CLI 的 `run` 命令默认使用 `-m "live and not destructive"` 模式。
破坏性测试会有意改变实时的认证、会话、API-key、撤销或速率限制状态,以证明堆栈在遭受攻击时的行为。它们可能会触发登录锁定、撤销会话或 token、消耗速率限制计数器、创建或修改测试用户/API keys,或者导致后续测试失败,直到堆栈状态过期或被重置。仅当这种副作用是可以接受时才运行它们。
推荐的常规运行:
```
security-tests-m8 run --env-file test.env
```
包含大量变更操作的完整运行:
```
security-tests-m8 run --env-file test.env --include-destructive
pytest --live-env-file test.env --pyargs security_tests_m8.full_security -m live
```
等效的非破坏性 pytest 运行:
```
pytest --live-env-file test.env --pyargs security_tests_m8.full_security -m "live and not destructive"
```
## 快速开始:pytest
当你需要自定义本地测试、本地套件子类或直接使用 pytest 标记选择时,请使用 pytest 模式:
```
pytest --live-env-file test.env --pyargs security_tests_m8.full_security
pytest --live-env-file test.env tests/live
pytest --live-env-file test.env --pyargs security_tests_m8.full_security -m live_deployment
```
该包通过 `pytest11` 入口点将自己注册为 pytest 插件。`--live-env-file` 会加载与 CLI 模式相同的实时测试 env 文件,而 `--live-env-override` 允许文件中的值替换现有的进程环境变量。
对于自定义的本地测试,请创建一个导入已打包套件的文件:
```
from security_tests_m8.full_security import * # noqa: F403
```
## 工作原理
该包包含三个部分:
1. 配置存储在进程级别的 `LiveTestConfig` 中。你可以通过 `security_tests_m8.configure(...)` 或环境变量来设置它。
2. pytest 插件暴露了诸如 `admin_token`、`admin_headers`、`regular_user`、`stack_config`、`service_base_url` 和 `service_url` 等 fixtures。
3. 套件类包含实际的测试。你的项目导入一个套件并继承它,这会使 pytest 在你的项目中收集这些测试。
当 `fail_fast_preflight=True` 时,插件会在收集之前检查认证健康状况、已配置的服务可用性、专用测试超级用户登录以及引导超级用户的滥用情况。如果堆栈不可用或凭据错误,pytest 会在整套测试触发锁定之前退出。
在收集阶段,插件会探测已配置的认证堆栈,并自动跳过与当前部署不匹配的测试。例如,在 HS256 堆栈上会跳过仅适用于 RS256 的测试,如果 Redis 不可用,则会跳过有状态的 Redis 检查。
## 配置
你可以使用 Python 进行配置:
```
from pathlib import Path
from security_tests_m8 import configure
configure(
auth_base_url="http://localhost:9000/user",
admin_email="admin@example.com",
admin_password="changethis",
service_base_url="http://localhost:9000/fastapi",
timeout=10,
repo_root=Path(__file__).parents[2],
deployment_root=Path(__file__).parents[2] / "examples/docker_compose/hardened_m8",
public_base_url="https://localhost:4430",
public_tls_verify=False,
private_api_secret="changethis",
private_api_client_id="media-service",
refresh_secret_key="changethis",
)
```
或者使用由 CLI `run`、pytest `--live-env-file` 或 `configure_from_env()` 加载的实时测试 env 文件:
```
LIVE_TEST_AUTH_BASE=http://localhost:9000/user
LIVE_TEST_INTERNAL_AUTH_BASE=http://localhost:9000/user
LIVE_TEST_AUTH_HEALTH_URL=http://localhost:9000/user/health/
LIVE_TEST_ADMIN_EMAIL=tester@example.com
LIVE_TEST_ADMIN_PASSWORD=change-this-test-password
LIVE_TEST_SVC_BASE=http://localhost:9000/fastapi
LIVE_TEST_TIMEOUT=10
LIVE_TEST_FAIL_FAST_PREFLIGHT=true
LIVE_TEST_FORBID_BOOTSTRAP_SUPERUSER=true
LIVE_TEST_DEPLOYMENT_ROOT=/path/to/repo/examples/docker_compose/hardened_m8
LIVE_TEST_PUBLIC_BASE=https://localhost:4430
LIVE_TEST_PUBLIC_TLS_VERIFY=false
```
对于使用自签名 Traefik 证书的本地 HTTPS 堆栈,设置
`LIVE_TEST_PUBLIC_TLS_VERIFY=false` 以禁用对配置的
实时测试目标 URL 的验证,或者将其设置为证书包路径,例如
`/path/to/hardened_m8/traefik/certs/local.crt`。
### 环境变量
| 变量 | 用途 | 默认值 |
| --- | --- | --- |
| `LIVE_TEST_AUTH_BASE` | 认证服务的 Base URL | `http://localhost:9000/user` |
| `LIVE_TEST_INTERNAL_AUTH_BASE` | 暴露 `/private/*` 的内部服务间入口。加固堆栈在公共边缘屏蔽 `/private` (Traefik → 404),因此 F06 针对每个消费者的旧版结构检查以此 URL 为目标。未设置时回退到 `LIVE_TEST_AUTH_BASE` | 未设置 |
| `LIVE_TEST_AUTH_HEALTH_URL` | 用于就绪状态和堆栈检测的可选私有/内部认证健康检查 URL | 未设置 |
| `LIVE_TEST_ADMIN_EMAIL` | 管理员登录邮箱 | `admin@example.com` |
| `LIVE_TEST_ADMIN_PASSWORD` | 管理员登录密码 | `changethis` |
| `LIVE_TEST_SVC_BASE` | 单个/默认下游服务 URL | 未设置 |
| `LIVE_TEST_SVC_BASES` | 命名服务 URL 的 JSON 对象 | `{}` |
| `LIVE_TEST_DEFAULT_SVC` | `LIVE_TEST_SVC_BASES` 中的默认服务名称 | 未设置 |
| `LIVE_TEST_TIMEOUT` | 请求超时时间(秒) | `10` |
| `LIVE_TEST_REPO_ROOT` | 用于发现已提交 JWT 密钥的仓库根目录 | 未设置 |
| `LIVE_TEST_DEPLOYMENT_ROOT` | `DeploymentPreflightSuite` 使用的 Compose 部署目录 | 未设置 |
| `LIVE_TEST_PUBLIC_BASE` | 用于公共/私有路由检查的公共 HTTPS 入口 | `https://localhost:4430` |
| `LIVE_TEST_PUBLIC_TLS_VERIFY` | 配置的实时测试 HTTPS 目标 URL 的 TLS 验证设置;对于本地自签名堆栈,请使用 `false` 或 CA 证书包路径 | `true` |
| `LIVE_TEST_PRIVATE_API_SECRET` | 用于私有 API 测试的 Secret header 值 (`X-Internal-Token`) | 未设置 |
| `LIVE_TEST_PRIVATE_API_CLIENT_ID` | fa-auth-m8 >= 1.0.0 issuer 的消费者 ID (`X-Internal-Client`);对于旧版的单密钥堆栈请保持未设置状态 | 未设置 |
| `LIVE_TEST_HEALTH_DETAIL_CREDENTIAL` | 解锁深层 `/health` 基础架构详情(token 模式、Redis/DB)的专用凭据 (`X-Internal-Token`);对于旧版堆栈,回退到 `LIVE_TEST_PRIVATE_API_SECRET` | 未设置 |
| `LIVE_TEST_REFRESH_SECRET_KEY` | refresh/cookie 测试使用的 Refresh-token secret | 未设置 |
| `LIVE_TEST_FAIL_FAST_PREFLIGHT` | 如果认证、服务或凭据不可用,在收集前中止 | `false` |
| `LIVE_TEST_FORBID_BOOTSTRAP_SUPERUSER` | 拒绝将来自 `auth.env` 的 `FIRST_SUPERUSER` 作为测试账户 | `true` |
| `LIVE_TEST_PROTECTED_ENDPOINTS` | 服务名称到受保护 endpoint 数组的 JSON 对象 | `{}` |
## 选择 Env 文件
`test.env` 用于配置测试运行器。它应该包含 `LIVE_TEST_*` 值,例如 `LIVE_TEST_AUTH_BASE`、`LIVE_TEST_ADMIN_EMAIL`、`LIVE_TEST_ADMIN_PASSWORD`、`LIVE_TEST_SVC_BASES` 和 `LIVE_TEST_DEPLOYMENT_ROOT`。`LIVE_TEST_PRIVATE_API_SECRET` 和 `LIVE_TEST_REFRESH_SECRET_KEY` 是可选的自愿启用值;仅当你希望进行 Secret 暴露检查(即使用真实的堆栈 secret 伪造请求)时才设置它们。
部署环境变量文件用于配置堆栈本身。诸如 `.env`、`auth.env`、`api.env`、`media.env`、`grafana/.env` 等文件,以及部署根目录下任何非示例的 `*.env` 文件,都会被部署预检扫描。诸如 `.env.example`、`auth.env.example`、`api.env.example`、`media.env.example`、`grafana/.env.example` 和 `test.env.example` 等示例/模板文件将被有意忽略。如果你将 `test.env` 放在部署根目录下,请不要在其中留下诸如 `changethis` 之类的占位符值,因为预检会报告它们。
## 部署环境预检
部署预检扫描程序会检查 compose env 文件和内联的 compose `environment:` 值中是否存在占位符密钥、重复的高价值密钥、不安全的生产设置、默认凭据,以及加固/生产堆栈中未固定版本的镜像。
```
security-tests-m8 preflight --deployment-root .
security-tests-m8 preflight --env-file test.env
security-tests-m8 preflight --deployment-root . --strict-warnings
```
它会打印出所扫描的准确 env 和 compose 文件、所有发现的问题、明确的 PASS/FAIL 结果、产生该结果的原因,以及需要采取的操作。当没有错误时它退出代码为 `0`,当存在错误时退出代码为 `1`。警告会被打印出来,但只有在使用--strict-warnings` 时才会使命令失败。
## CLI 与 pytest 模式
CLI 模式对于非高级用户来说是最简单的路径:指向一个 env 文件并运行打包的套件,而无需添加本地的 pytest 文件。它默认排除 `destructive` 测试;当你有意希望获得包含大量变更操作的全面覆盖时,请使用 `--include-destructive`。对于希望进行自定义测试、自定义套件子类、特定项目的 fixtures 或直接使用 pytest 标记表达式的团队来说,Pytest 模式是合适的选择。
两种模式都使用相同的配置模型和相同的可重用套件。
## 单服务用法
对于只有一个下游服务的项目,请配置 `service_base_url`,并针对你要验证的每个受保护 endpoint 继承 `ProtectedEndpointSuite`。
```
from security_tests_m8 import configure
configure(
auth_base_url="http://localhost:9000/user",
service_base_url="http://localhost:9000/fastapi",
admin_email="admin@example.com",
admin_password="change-me",
)
```
```
from security_tests_m8.suites import ProtectedEndpointSuite
class TestCategories(ProtectedEndpointSuite):
endpoint = "/category/"
class TestDashboardActivity(ProtectedEndpointSuite):
endpoint = "/dashboard/users/activity/"
```
每个受保护的 endpoint 套件会检查:
- 缺少 token 会被拒绝,返回 `401` 或 `403`
- 无效的 bearer token 会被拒绝,返回 `401` 或 `403`
- 有效的管理员 access token 会被接受,返回 `200`
## 多服务用法
对于包含多个 FastAPI M8 服务的堆栈,请配置一个命名的 URL 映射。
```
from security_tests_m8 import configure
configure(
auth_base_url="http://localhost:9000/user",
service_base_urls={
"catalog": "http://localhost:9000/catalog",
"orders": "http://localhost:9000/orders",
"billing": "http://localhost:9000/billing",
},
default_service="catalog",
admin_email="admin@example.com",
admin_password="change-me",
)
```
同样的设置也可以通过 shell 提供:
```
export LIVE_TEST_SVC_BASES='{"catalog":"http://localhost:9000/catalog","orders":"http://localhost:9000/orders","billing":"http://localhost:9000/billing"}'
export LIVE_TEST_DEFAULT_SVC="catalog"
```
然后为每个测试类选择服务:
```
from security_tests_m8.suites import ProtectedEndpointSuite
class TestCatalogCategories(ProtectedEndpointSuite):
service = "catalog"
endpoint = "/category/"
class TestOrderList(ProtectedEndpointSuite):
service = "orders"
endpoint = "/orders/"
```
如果某个套件指定了一个未配置的服务,setup 将会失败,并列出已知的明确服务名称列表。
## 可用测试套件
通用认证与 HTTP 安全套件:
- `AuthAttackSuite`
- `JWTStructuralSuite`
- `AuthorizationSuite`
- `RateLimitingSuite`
- `CORSSuite`
- `PrivateAPISuite`
- `MetricsAPISuite`
- `HealthAPISuite`
- `AvatarUrlSuite`
- `InfoDisclosureSuite`
- `SecurityHeadersSuite`
- `CookieSecuritySuite`
- `ApiKeySuite`
Token 模式套件:
- `StatelessContractSuite`
- `StatefulRevocationSuite`
- `StatefulAccessRevocationSuite`
- `HybridContractSuite`
JWT 算法套件:
- `AsymmetricJWTSuite`
- `JWKSSuite`
- `CrossServiceTokenSuite`
- `HS256Suite`
- `HS256WeakKeySuite`
通用服务与部署套件:
- `ProtectedEndpointSuite`
- `ConfiguredProtectedEndpointsSuite`
- `ServiceInfoDisclosureSuite`
- `ConfiguredServiceInfoDisclosureSuite`
- `DeploymentPreflightSuite`
## 完整的认证服务示例
```
from security_tests_m8.suites import (
ApiKeySuite,
AsymmetricJWTSuite,
AuthAttackSuite,
AuthorizationSuite,
AvatarUrlSuite,
CookieSecuritySuite,
CORSSuite,
CrossServiceTokenSuite,
HealthAPISuite,
HS256Suite,
HS256WeakKeySuite,
HybridContractSuite,
InfoDisclosureSuite,
JWKSSuite,
JWTStructuralSuite,
MetricsAPISuite,
PrivateAPISuite,
RateLimitingSuite,
SecurityHeadersSuite,
StatefulAccessRevocationSuite,
StatefulRevocationSuite,
StatelessContractSuite,
)
class TestAuthAttacks(AuthAttackSuite):
pass
class TestJWTStructure(JWTStructuralSuite):
pass
class TestAuthorization(AuthorizationSuite):
pass
class TestRateLimiting(RateLimitingSuite):
pass
class TestCORS(CORSSuite):
pass
class TestPrivateAPI(PrivateAPISuite):
pass
class TestMetrics(MetricsAPISuite):
pass
class TestHealth(HealthAPISuite):
pass
class TestAvatarUrls(AvatarUrlSuite):
pass
class TestInfoDisclosure(InfoDisclosureSuite):
pass
class TestSecurityHeaders(SecurityHeadersSuite):
pass
class TestCookieSecurity(CookieSecuritySuite):
pass
class TestApiKeys(ApiKeySuite):
pass
class TestStatelessMode(StatelessContractSuite):
pass
class TestStatefulRevocation(StatefulRevocationSuite):
pass
class TestStatefulAccessRevocation(StatefulAccessRevocationSuite):
pass
class TestHybridMode(HybridContractSuite):
pass
class TestAsymmetricJWT(AsymmetricJWTSuite):
pass
class TestJWKS(JWKSSuite):
pass
class TestCrossServiceTokens(CrossServiceTokenSuite):
pass
class TestHS256(HS256Suite):
pass
class TestHS256WeakKeys(HS256WeakKeySuite):
pass
```
## Pytest 标记
该插件注册了以下标记:
- `live`
- `live_security`
- `live_asymmetric`
- `live_hs256`
- `live_stateful`
- `live_stateless`
- `live_hybrid`
- `live_deployment`
- `require_algorithm(*names)`
- `require_token_mode(*names)`
- `require_redis`
- `destructive`
常用命令:
```
pytest tests/live -m live
pytest tests/live -m "live and not destructive"
pytest tests/live -m live_asymmetric
pytest tests/live -m live_hs256
pytest tests/live -m live_stateful
pytest tests/live -m live_stateless
pytest tests/live -m live_hybrid
```
## 暴露的 Fixtures
在安装了该包之后,消费者测试中可以使用以下 fixtures:
- `stack_config`
- `admin_token`
- `admin_headers`
- `admin_login`
- `regular_user` — 作用于会话级别;创建一个一次性的 `redteam_@redteam-test.com` 非超级用户,并在会话结束时(尽最大努力,通过管理员账户)将其删除
- `live_jwks_keys`
- `committed_key_forge`
- `public_key_pem`
- `asymmetric_key_pem`
- `service_base_urls`
- `service_base_url`
- `service_url`
示例:
```
def test_custom_protected_route(service_url, admin_headers):
import requests
response = requests.get(
f"{service_url('catalog')}/category/",
headers=admin_headers,
timeout=10,
)
assert response.status_code == 200
```
## 实时堆栈注意事项
- 测试使用配置的专用纯测试超级用户来创建 token,并且对于某些套件,还会创建一个临时的普通用户。
- **一次性 `redteam_*` 用户。** `regular_user` fixture 会在每个会话中创建一个普通(非超级)用户账户,使用格式为 `redteam_@redteam-test.com` 的随机邮箱(密码为 `RedTeam!Pass99`),用于证明普通用户无法提升权限或访问仅限管理员的 routes。该 fixture **会在会话结束时通过管理员账户删除该用户**,因此常规运行不会留下长期存在的测试身份。删除操作是尽最大努力的:如果在运行 teardown 时堆栈不可达,该账户可能会残留,并且可以手动清理(通过 `redteam_*@redteam-test.com` 模式进行过滤)。你配置的专用**超级用户**绝不会由套件创建或删除——它必须事先存在,并由你自行管理。
- 不要使用堆栈的引导超级用户(`FIRST_SUPERUSER`)作为实时测试账户。在启用了 fail-fast 预检的情况下,该包默认会拒绝此配置。
- 一些测试被标记为 `destructive`,因为它们会执行撤销、速率限制、API key 变更或其他实时状态更改操作。CLI `run` 默认排除这些测试;传递 `--include-destructive` 以运行它们。
- 当算法和特定 token 模式的测试与检测到的堆栈不匹配时,它们会被自动跳过。
- `repo_root` 或 `LIVE_TEST_REPO_ROOT` 仅在尝试将实时 JWKS keys 与已提交的私钥进行比较的测试中才需要。
- `deployment_root` 或 `LIVE_TEST_DEPLOYMENT_ROOT` 启用用于 compose env/镜像检查的 Python 部署预检套件。
- `public_tls_verify=False` 对于使用自签名证书的本地 HTTPS 堆栈很有用。
- `LIVE_TEST_PRIVATE_API_SECRET` 和 `LIVE_TEST_REFRESH_SECRET_KEY` 是可选启用的检查。将它们留空以跳过这些检查,或者将它们设置为目标堆栈中的真实值。
- `LIVE_TEST_PRIVATE_API_CLIENT_ID` 是作为 `X-Internal-Client` 与 `X-Internal-Token` 一起发送的每个消费者的 ID,以便私有 API 探测能够针对基于每个消费者的 issuer (fa-auth-m8 >= 1.0.0,无共享密钥回退) 进行认证。将其与 `LIVE_TEST_PRIVATE_API_SECRET` 一起设置也可启用 F06 旧版检测检查(已废弃的、仅包含 `X-Internal-Token` 的结构必须被拒绝并返回 401)。对于旧版的单密钥堆栈,请将其留空。
- `LIVE_TEST_INTERNAL_AUTH_BASE` 是暴露 `/private/*` 的内部服务间入口。加固堆栈在公共边缘屏蔽 `/private` (Traefik → 404),因此 F06 旧版结构拒绝只能在内部入口上观察到。当 `LIVE_TEST_AUTH_BASE` 指向公共边缘时,将其设置为该 URL(例如 `http://localhost:9000/user`);未设置时它将回退到 `LIVE_TEST_AUTH_BASE`,这对于那些 Base 能直接到达私有 routes 的简单堆栈来说是正确的。
- `LIVE_TEST_HEALTH_DETAIL_CREDENTIAL` 解锁用于堆栈检测以及 token 模式/信息泄露套件的深层 `/health` 基础架构详情响应体(token 模式、Redis/DB 可达性、降级模式)。fa-auth-m8 >= 1.0.0 将该详情限制在与 `PRIVATE_API_SECRET` 解耦的专用凭据之后(方案 9.3),并通过 `X-Internal-Token` 发送。将其设置为堆栈的 `HEALTH_DETAIL_CREDENTIAL`,以便那些依赖健康状态的测试可以读取所需内容;仅在旧版堆栈(仍然将其复用于健康检查门控)时,探测才会回退到 `LIVE_TEST_PRIVATE_API_SECRET`。
## 开发
安装带有开发依赖的包:
```
pip install -e ".[dev]"
```
运行本地单元测试:
```
pytest
```
根据需要使用你的项目工具运行格式化和 linting。该包使用来自 `pyproject.toml` 的 Ruff 设置。
## 示例
在 [`examples/hardened_m8_full_security/`](examples/hardened_m8_full_security/) 中提供了一个可直接运行的完整安全测试示例。
此示例针对 `fa-auth-m8` 加固的 Docker Compose 堆栈运行完整的可重用套件:
- 被测试的 compose 堆栈:[`mano8/fa-auth-m8/examples/docker_compose/hardened_m8`](https://github.com/mano8/fa-auth-m8/tree/main/examples/docker_compose/hardened_m8)
- 本地工作区路径:`/workspace/fa-auth-m8/examples/docker_compose/hardened_m8`
- 本仓库中的示例:[`mano8/security-tests-m8/examples/hardened_m8_full_security`](https://github.com/mano8/security-tests-m8/tree/main/examples/hardened_m8_full_security)
加固堆栈使用 RS256 access token、有状态 token 模式、由 Redis 支持的撤销机制、PostgreSQL、Traefik、Prometheus、Grafana,以及暴露在 `/fastapi` 的示例 `fastapi_full` 消费者。该示例需要一个专用的纯测试超级用户。CLI 模式加载通过 `--env-file` 传递的文件;本地 pytest 示例通过 `tests/live/conftest.py` 从其自身目录加载 `.env`。
`hardened_m8` 仅作为参考目标。只需调整配置(认证/服务 URL、受保护的 endpoint、部署根目录和 TLS 设置),该示例即可针对**任何使用 `fa-auth-m8` 作为 issuer 且使用基于 `fastapi-m8` 的消费者的 compose 堆栈**运行 —— 无论是最小化、预发布还是生产环境。该示例的两个随时可适配的副本位于它们所测试的堆栈旁边:
- [`fa-auth-m8/examples/docker_compose/shared_live_tests`](https://github.com/mano8/fa-auth-m8/tree/main/examples/docker_compose/shared_live_tests)
- [`media-service-m8/docker_compose/shared_live_tests`](https://github.com/mano8/media-service-m8/tree/main/docker_compose/shared_live_tests)
标签:API安全, JSON输出, Python, 安全测试, 安全规则引擎, 攻击性安全, 无后门, 版权保护, 逆向工具