# Sécurité locale

> Exigences de sécurité des services LMSP, avec liaison à loopback, appairage et jetons porteurs, portées, vérifications d’Origin et de Host contre les pages web malveillantes, mode LAN et règles de journalisation.

Source: https://madeforagent.com/fr/lmsp/1.0/security/
Language: fr
Specification: LMSP 1.0 (draft)
Updated: 2026-11-08

## 10.1 Socle {#baseline}

Écouter uniquement sur localhost n’offre pas une sécurité absolue : une page web malveillante peut toujours essayer d’atteindre les ports locaux. LMSP combine donc plusieurs mesures.

- Un service **DOIT** se lier par défaut aux adresses de loopback. Il **NE DOIT PAS** écouter sur `0.0.0.0`, ni sur aucune autre adresse hors loopback, sauf si le mode LAN est activé ([section 10.5](https://madeforagent.com/fr/lmsp/1.0/security.md#lan)).
- Au premier lancement, un service **DEVRAIT** générer un secret de service aléatoire à forte entropie, et l’utiliser, plutôt que toute valeur par défaut intégrée, pour émettre et vérifier les jetons.
- Chaque requête vers l’interface principale **DOIT** porter un jeton porteur valide, sauf pour les points de terminaison d’amorçage listés à la [section 4.2](https://madeforagent.com/fr/lmsp/1.0/endpoints.md#conventions). Provenir de loopback ne suffit jamais à lui seul.

## 10.2 Appairage et jetons {#pairing}

Un client obtient son propre jeton porteur grâce à un code d’appairage local. L’utilisateur demande au service d’afficher un code d’appairage, de la manière que le service propose, et le client le soumet :

```http
POST /lmsp/v1/pair
Content-Type: application/json
```

```json
{
  "client_name": "example-client",
  "pairing_code": "K7QD-4M2X",
  "scopes": ["inference"]
}
```

| Champ de la requête | Signification |
| --- | --- |
| `client_name` | Nom d’affichage du client, montré à l’utilisateur. |
| `pairing_code` | Le code que l’utilisateur a obtenu auprès du service. |
| `scopes` | Liste facultative de portées demandées. Vaut `["inference"]` par défaut. |

Le service répond avec un jeton. Le `token_type` vaut toujours `Bearer` :

```json
{
  "client_id": "cli_01J8MAT3W6X9B2D5F8H1K4N7QZ",
  "access_token": "lmsp_example_3f9a1c52e7d84b60",
  "token_type": "Bearer",
  "scopes": ["inference"]
}
```

Le client envoie ensuite `Authorization: Bearer <token>` avec chaque requête.

- Un code d’appairage **DOIT** être à usage unique et **DEVRAIT** expirer en 5 minutes. Il **DEVRAIT** porter au moins 40 bits d’entropie. Un service **DOIT** limiter le débit des tentatives échouées. Un code erroné ou expiré reçoit la réponse `401` avec `unauthorized`.
- Les jetons sont indépendants pour chaque client, de sorte que l’utilisateur peut en révoquer un sans affecter les autres. Un service **DEVRAIT** permettre à l’utilisateur de lister et de révoquer les clients appairés.
- Un client **DEVRAIT** conserver son jeton dans le trousseau ou le gestionnaire d’identifiants du système d’exploitation. Un service **DEVRAIT** ne stocker qu’une empreinte de chaque jeton.
- Un jeton absent, invalide ou révoqué reçoit la réponse `401`, `unauthorized` et un en-tête `WWW-Authenticate: Bearer`. Un jeton valide qui n’a pas la portée dont un point de terminaison a besoin reçoit la réponse `403` avec `forbidden`.

## 10.3 Portées {#scopes}

Les autorisations sont réparties en portées distinctes. Télécharger des modèles, supprimer des modèles et exécuter des outils ne passent jamais par la portée d’inférence.

| Portée | Autorise |
| --- | --- |
| `inference` | Lire le catalogue de modèles, créer des réponses et des tâches, et lire et annuler les tâches du client lui-même. |
| `models:manage` | Charger et décharger des modèles. |
| `models:install` | Réservé. Télécharger et supprimer des modèles. |
| `tools:execute` | Réservé. Exécuter des outils côté service. |

Les tâches et les réponses stockées appartiennent au client qui les a créées. Un service **DEVRAIT** répondre à la requête d’un autre client comme si elles n’existaient pas (`task_not_found` ou `response_not_found`).

## 10.4 Protections du navigateur et du réseau {#browser}

- Un service **DOIT** rejeter par défaut les requêtes de navigateur inter-origines, et n’autoriser que les valeurs d’`Origin` explicitement configurées. Une requête avec toute autre `Origin` reçoit la réponse `403` avec `forbidden`.
- Lorsqu’une origine est autorisée, le service répond à ses requêtes de pré-vérification CORS et envoie `Access-Control-Allow-Origin` avec cette origine exacte, jamais avec `*`.
- Un service **DOIT** valider l’en-tête `Host`, pour empêcher le DNS rebinding. Il n’accepte que les noms d’hôte qu’il sert : les noms et adresses de loopback, plus les noms configurés pour le mode LAN. Toute autre valeur reçoit la réponse `403` avec `forbidden`.

## 10.5 Mode LAN {#lan}

Le mode LAN signifie écouter au-delà des adresses de loopback.

- Un service **NE DOIT PAS** activer le mode LAN sauf si l’utilisateur l’active explicitement.
- En mode LAN, un service **DOIT** exiger une authentification, et **DEVRAIT** aussi activer TLS. Un client **NE DEVRAIT PAS** envoyer de jeton en HTTP non chiffré à une adresse hors loopback, sauf si l’utilisateur l’autorise explicitement.
- L’annonce mDNS n’est permise qu’en mode LAN, lorsque l’utilisateur a aussi activé la découverte sur le réseau local ([section 3.2](https://madeforagent.com/fr/lmsp/1.0/discovery.md#mdns)).

## 10.6 Journalisation et vie privée {#logging}

- Les chemins de modèles, les journaux, les prompts et le contenu généré **NE DOIVENT PAS** apparaître dans les annonces mDNS.
- Par défaut, un service **DEVRAIT** ne journaliser que des métadonnées (dates, points de terminaison, codes d’état, identifiants, nombres de tokens et durées). Il **NE DEVRAIT PAS** journaliser les prompts complets ni le contenu généré.
- Les réponses de santé et les détails d’erreur **NE DOIVENT PAS** contenir de chemins de modèles, de prompts, de jetons d’accès ni d’autres informations sensibles.
