Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac05da7001 | ||
|
|
cfc194a3fb | ||
|
|
59f050ec5e |
@@ -16,6 +16,9 @@ EN_TETES: Final[dict[str, str]] = {
|
|||||||
"X-Content-Type-Options": "nosniff",
|
"X-Content-Type-Options": "nosniff",
|
||||||
"X-Frame-Options": "DENY",
|
"X-Frame-Options": "DENY",
|
||||||
"Referrer-Policy": "no-referrer",
|
"Referrer-Policy": "no-referrer",
|
||||||
|
# same-origin : aucun client ne charge l'API en no-cors depuis une autre origine
|
||||||
|
# (proxy.conf.json en dev, reverse proxy nginx ensuite, cf. docs/architecture/20-backend.md).
|
||||||
|
"Cross-Origin-Resource-Policy": "same-origin",
|
||||||
}
|
}
|
||||||
|
|
||||||
PREFIXE_AUTHENTIFICATION: Final = "/auth"
|
PREFIXE_AUTHENTIFICATION: Final = "/auth"
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ async def interroge(
|
|||||||
("x-content-type-options", "nosniff"),
|
("x-content-type-options", "nosniff"),
|
||||||
("x-frame-options", "DENY"),
|
("x-frame-options", "DENY"),
|
||||||
("referrer-policy", "no-referrer"),
|
("referrer-policy", "no-referrer"),
|
||||||
|
("cross-origin-resource-policy", "same-origin"),
|
||||||
],
|
],
|
||||||
ids=["nosniff", "anti_iframe", "referrer"],
|
ids=["nosniff", "anti_iframe", "referrer", "corp"],
|
||||||
)
|
)
|
||||||
async def test_every_response_carries_the_security_headers(
|
async def test_every_response_carries_the_security_headers(
|
||||||
client: AsyncClient, entete: str, valeur: str
|
client: AsyncClient, entete: str, valeur: str
|
||||||
|
|||||||
@@ -423,8 +423,13 @@ Le reste, par ordre de surface :
|
|||||||
écriture des journaux. C'est la troisième ligne de défense : la première est de ne rien passer
|
écriture des journaux. C'est la troisième ligne de défense : la première est de ne rien passer
|
||||||
de secret au logger, la deuxième de ne jamais mettre un jeton dans une URL.
|
de secret au logger, la deuxième de ne jamais mettre un jeton dans une URL.
|
||||||
- En-têtes posés par l'application : `X-Content-Type-Options`, `X-Frame-Options`,
|
- En-têtes posés par l'application : `X-Content-Type-Options`, `X-Frame-Options`,
|
||||||
`Referrer-Policy`, plus `Cache-Control: no-store` sur `/auth/*`. HSTS et CSP appartiennent au
|
`Referrer-Policy`, `Cross-Origin-Resource-Policy: same-origin`, plus `Cache-Control: no-store`
|
||||||
terminateur TLS, que l'application ne connaît pas : le reverse proxy les pose
|
sur `/auth/*`. Le CORP est fixé à `same-origin` parce qu'aucun client légitime ne charge l'API
|
||||||
|
en `no-cors` (image, script, média) depuis une autre origine : le frontend l'appelle en relatif
|
||||||
|
(`/api/v1`), sur sa propre origine, via `proxy.conf.json` en dev et le reverse proxy nginx
|
||||||
|
(`infra/proxy/conf.d/enervision.conf`) en recette et en production. Les appels `HttpClient`, en
|
||||||
|
mode `cors`, n'y sont de toute façon pas soumis. HSTS et CSP appartiennent au terminateur TLS, que
|
||||||
|
l'application ne connaît pas : le reverse proxy les pose
|
||||||
([ADR 0007](../adr/0007-terminaison-tls-et-reverse-proxy-nginx.md)).
|
([ADR 0007](../adr/0007-terminaison-tls-et-reverse-proxy-nginx.md)).
|
||||||
- Le conteneur tourne en utilisateur non-root, avec un `HEALTHCHECK` sur `/api/v1/health/live`.
|
- Le conteneur tourne en utilisateur non-root, avec un `HEALTHCHECK` sur `/api/v1/health/live`.
|
||||||
- TLS, limitation de débit au frontal et journal d'accès sont portés par le reverse proxy.
|
- TLS, limitation de débit au frontal et journal d'accès sont portés par le reverse proxy.
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ lecture seule ; plusieurs lignes resteront à compléter une fois les endpoints
|
|||||||
| Cinq gardes de configuration qui refusent le démarrage plutôt que de dégrader silencieusement | `app/core/config.py` | A05 |
|
| Cinq gardes de configuration qui refusent le démarrage plutôt que de dégrader silencieusement | `app/core/config.py` | A05 |
|
||||||
| Documentation interactive fermée hors développement, `/metrics` derrière un jeton, sonde qui ne publie plus de version | `app/main.py`, `app/api/security.py` | A05 |
|
| Documentation interactive fermée hors développement, `/metrics` derrière un jeton, sonde qui ne publie plus de version | `app/main.py`, `app/api/security.py` | A05 |
|
||||||
| Scan dynamique OWASP ZAP de l'API authentifiée (compte `lecteur` jetable), non bloquant, configuration par défaut du backend uniquement (ni TLS ni en-têtes du reverse proxy) | `.github/workflows/dast.yml`, `scripts/dast-token.sh` | A05, API8 Security Misconfiguration |
|
| Scan dynamique OWASP ZAP de l'API authentifiée (compte `lecteur` jetable), non bloquant, configuration par défaut du backend uniquement (ni TLS ni en-têtes du reverse proxy) | `.github/workflows/dast.yml`, `scripts/dast-token.sh` | A05, API8 Security Misconfiguration |
|
||||||
| En-têtes `nosniff`, `DENY`, `no-referrer`, et `no-store` sur les routes d'authentification | `app/api/middleware.py` | A05 |
|
| En-têtes `nosniff`, `DENY`, `no-referrer`, `Cross-Origin-Resource-Policy: same-origin`, et `no-store` sur les routes d'authentification | `app/api/middleware.py` | A05 |
|
||||||
| Refus de rétrograder ou désactiver le dernier administrateur actif | `app/services/user.py` | A04 Insecure Design |
|
| Refus de rétrograder ou désactiver le dernier administrateur actif | `app/services/user.py` | A04 Insecure Design |
|
||||||
| Amorçage du premier administrateur hors dépôt, mot de passe jamais dans `argv` ni dans Git | `app/cli.py` | A02, A05 |
|
| Amorçage du premier administrateur hors dépôt, mot de passe jamais dans `argv` ni dans Git | `app/cli.py` | A02, A05 |
|
||||||
| Réponse de l'API Mock bornée avant écriture : timeout, plafond de sites et de mesures, bornes physiques par grandeur, recopie des seuls champs attendus | `app/etl/mock_api_import.py` | API10 Unsafe Consumption of APIs |
|
| Réponse de l'API Mock bornée avant écriture : timeout, plafond de sites et de mesures, bornes physiques par grandeur, recopie des seuls champs attendus | `app/etl/mock_api_import.py` | API10 Unsafe Consumption of APIs |
|
||||||
|
|||||||
Reference in New Issue
Block a user