---
title: Securite
description: Politique de securite et mesures de protection de libreDecision
---

# Securite

Ce document decrit les mesures de securite implementees dans libreDecision pour proteger l'integrite de la plateforme, des votes et des donnees des utilisateurs.

## Authentification Duniter V2 (Ed25519 challenge-response)

### Principe

libreDecision n'utilise ni mot de passe ni systeme d'inscription classique. L'authentification repose entierement sur la cryptographie Ed25519 de la blockchain Duniter V2.

### Flux challenge-response

```
Client                              Serveur
  |                                    |
  |-- POST /auth/challenge ----------->|
  |   { address: "5Grw..." }          |
  |                                    |-- Genere challenge (64 hex)
  |                                    |-- Stocke en memoire (TTL 5 min)
  |<-------- { challenge: "a1b2..." } -|
  |                                    |
  |-- Signe le challenge localement   |
  |   (cle privee Ed25519)            |
  |                                    |
  |-- POST /auth/verify ------------->|
  |   { address, challenge, signature}|
  |                                    |-- Verifie signature Ed25519
  |                                    |-- Verifie identite WoT
  |                                    |-- Cree/retrouve DuniterIdentity
  |                                    |-- Genere token de session
  |<-------- { token: "..." } --------|
```

### Garanties de securite

| Propriete | Mecanisme |
| --------- | --------- |
| **Cle privee jamais transmise** | Seule la signature est envoyee, pas la cle |
| **Anti-replay** | Chaque challenge est usage unique, expire apres 5 minutes |
| **Anti-interception** | HTTPS/TLS obligatoire en production |
| **Identite verifiee** | L'adresse SS58 est verifiee sur la blockchain via `substrate-interface` |

### Verification de la signature

```python
from substrateinterface import Keypair

keypair = Keypair(ss58_address=address)
is_valid = keypair.verify(challenge_bytes, signature_bytes)
```

La cle publique est derivee de l'adresse SS58 sans aucun appel reseau. La verification est locale et instantanee.

## Integrite des votes

### Signature cryptographique des votes

Chaque vote soumis est accompagne d'une **signature Ed25519** qui garantit son authenticite et son integrite.

### Payload signe

Le payload signe contient :

```json
{
  "session_id": "uuid-de-la-session",
  "vote_value": "for",
  "timestamp": "2026-02-28T12:00:00Z"
}
```

Ce payload est signe par la cle privee du votant. La signature est stockee en base de donnees avec le vote, permettant une verification independante a tout moment.

### Proprietes garanties

| Propriete | Description |
| --------- | ----------- |
| **Authenticite** | Seul le proprietaire de l'adresse Duniter peut soumettre un vote en son nom |
| **Integrite** | Le payload ne peut pas etre modifie apres signature sans invalider la signature |
| **Non-repudiation** | Le votant ne peut pas nier avoir vote ; la preuve cryptographique est publique |
| **Transparence** | Les votes signes sont publics et verifiables par quiconque |

### Verification d'un vote

```python
from substrateinterface import Keypair

keypair = Keypair(ss58_address=voter_address)
is_valid = keypair.verify(signed_payload.encode(), signature_bytes)
```

### Protection contre la modification

Quand un votant modifie son vote, l'ancien vote est marque `is_active = false` mais conserve en base. Les deux votes (ancien et nouveau) conservent leur signature. L'historique complet est auditable.

## Rate limiting

### Limites par endpoint

Pour prevenir les abus et les attaques par deni de service, des limites de taux sont appliquees :

| Categorie | Endpoints | Limite | Fenetre |
| --------- | --------- | ------ | ------- |
| Authentification | `/auth/challenge`, `/auth/verify` | 10 requetes | 1 minute |
| Vote | `/votes/sessions/{id}/vote` | 5 requetes | 1 minute |
| Ecriture | `POST`, `PUT`, `DELETE` | 30 requetes | 1 minute |
| Lecture | `GET` | 200 requetes | 1 minute |
| WebSocket | `/ws` | 3 connexions | simultanees par IP |

### Reponse en cas de depassement

Le serveur retourne un code HTTP **429 Too Many Requests** avec un header `Retry-After` indiquant le temps d'attente en secondes.

## En-tetes de securite

Les en-tetes HTTP suivants sont configures en production :

| En-tete | Valeur | Description |
| ------- | ------ | ----------- |
| `Strict-Transport-Security` | `max-age=63072000; includeSubDomains; preload` | Force HTTPS pendant 2 ans, inclut les sous-domaines |
| `Content-Security-Policy` | `default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' wss:; img-src 'self' data: https://ipfs.io` | Restreint les sources de contenu autorisees |
| `X-Content-Type-Options` | `nosniff` | Empeche le navigateur de deviner le type MIME |
| `X-Frame-Options` | `DENY` | Empeche l'inclusion dans un iframe (anti-clickjacking) |
| `X-XSS-Protection` | `1; mode=block` | Active la protection XSS du navigateur |
| `Referrer-Policy` | `strict-origin-when-cross-origin` | Limite les informations de referer |
| `Permissions-Policy` | `camera=(), microphone=(), geolocation=()` | Desactive les APIs sensibles non necessaires |

### CSP detaillee

La Content Security Policy est configuree pour :

- Autoriser les scripts uniquement depuis l'origine (`'self'`)
- Autoriser les styles inline (necessaires pour UnoCSS)
- Autoriser les connexions WebSocket (`wss:`)
- Autoriser les images depuis IPFS gateway (`https://ipfs.io`) pour l'affichage des contenus archives
- Bloquer tout le reste

## Sanctuaire : triple preuve d'integrite

### Chaine de verification

```
Contenu --> [SHA-256] --> hash
                |
                +---> [IPFS] --> CID (content-addressable)
                |
                +---> [system.remark on-chain] --> preuve horodatee
                |
                v
         Triple preuve :
         1. Hash local = hash enregistre (integrite)
         2. CID IPFS = contenu identique (distribution)
         3. Remark on-chain = hash confirme (immutabilite temporelle)
```

### Garanties

| Preuve | Ce qu'elle garantit | Point de defaillance |
| ------ | ------------------- | -------------------- |
| SHA-256 | Le contenu n'a pas ete modifie | Aucun (mathematique) |
| IPFS CID | Le contenu est distribue et adressable par contenu | Disponibilite des noeuds IPFS |
| On-chain remark | Le hash existait a la date du bloc | Securite de la blockchain Duniter |

### Format du remark on-chain

```
libredecision:sanctuary:{content_hash_sha256}
```

Le prefixe `libredecision:sanctuary:` permet d'identifier les ancrages de libreDecision parmi tous les remarks de la blockchain.

## WebSocket : authentification et securite

### Authentification par token

La connexion WebSocket est authentifiee via le token de session obtenu lors du challenge-response :

```
ws://server/api/v1/ws?token={session_token}
```

Le serveur verifie le token avant d'accepter la connexion. Les connexions non authentifiees sont rejetees.

### Protections WebSocket

| Protection | Description |
| ---------- | ----------- |
| Token valide requis | Pas de connexion anonyme |
| Limite de connexions | Maximum 3 connexions simultanees par IP |
| Heartbeat | Ping/pong periodique pour detecter les connexions mortes |
| Taille maximale des messages | Limite a 64 Ko pour prevenir les abus |
| Broadcast read-only | Les clients recoivent les mises a jour mais ne peuvent pas modifier l'etat via WebSocket |

## Session management

### Tokens de session

| Propriete | Valeur |
| --------- | ------ |
| Duree de vie (TTL) | 24 heures |
| Stockage serveur | Hash SHA-256 du token en base (table `sessions`) |
| Stockage client | Token en clair dans le `localStorage` du navigateur |
| Invalidation | Suppression de l'entree en base via `/auth/logout` |

### Securite des tokens

- Le token est genere avec un generateur cryptographiquement sur (CSPRNG)
- Seul le **hash** du token est stocke en base de donnees. Si la base est compromise, les tokens bruts ne sont pas exposes.
- A chaque requete authentifiee, le token fourni est hashe et compare au hash en base
- Les tokens expires sont nettoyes periodiquement

### Deconnexion

L'appel a `POST /auth/logout` invalide la session cote serveur en supprimant l'entree de la table `sessions`. Le client supprime le token de son `localStorage`.

## Audit logging

### Evenements traces

Les actions suivantes sont enregistrees pour auditabilite :

| Evenement | Donnees enregistrees |
| --------- | -------------------- |
| Authentification reussie | Adresse SS58, timestamp, IP |
| Authentification echouee | Adresse SS58, raison, timestamp, IP |
| Vote soumis | Session ID, voter ID, vote, signature, timestamp |
| Vote modifie | Session ID, voter ID, ancien vote (desactive), nouveau vote |
| Decision creee/avancee | Decision ID, auteur, action, timestamp |
| Document archive | Document ID, hash, CID, tx_hash |
| Session de vote cloturee | Session ID, resultat, seuils |
| Mandat assigne/revoque | Mandate ID, mandataire, action |

### Conservation

Les logs d'audit sont conserves de maniere permanente dans la base de donnees. Les votes et leurs signatures sont particulierement importants car ils constituent la preuve cryptographique des decisions collectives.

## Signalement de vulnerabilite (Responsible disclosure)

### Processus

Si vous decouvrez une vulnerabilite de securite dans libreDecision, merci de suivre cette procedure de divulgation responsable :

1. **Ne divulguez pas publiquement** la vulnerabilite avant qu'un correctif soit disponible.
2. **Contactez l'equipe** via le canal securise indique sur le depot Git Duniter ou via le forum Duniter (message prive aux mainteneurs).
3. **Decrivez la vulnerabilite** avec autant de details que possible :
   - Type de vulnerabilite (injection, XSS, CSRF, contournement d'authentification, etc.)
   - Etapes pour reproduire
   - Impact potentiel
   - Suggestion de correctif (si applicable)
4. **Delai de correction** : l'equipe s'engage a accuser reception sous 48 heures et a fournir un correctif sous 14 jours pour les vulnerabilites critiques.
5. **Credit** : les chercheurs en securite qui signalent des vulnerabilites de maniere responsable seront credites dans le changelog (sauf s'ils preferent l'anonymat).

### Perimetre

Le perimetre de la politique de securite couvre :

| Inclus | Exclus |
| ------ | ------ |
| API backend (FastAPI) | Infrastructure d'hebergement tiers |
| Frontend (Nuxt 4) | Blockchain Duniter V2 elle-meme |
| Authentification challenge-response | Extension Polkadot.js |
| Integrite des votes et signatures | Noeud IPFS (kubo) lui-meme |
| WebSocket | Traefik |
| Base de donnees (acces, injection) | -- |

### Exclusions

Les types de signalement suivants sont hors perimetre :

- Deni de service par volume (DDoS)
- Ingenierie sociale
- Attaques physiques sur l'infrastructure
- Vulnerabilites dans les dependances tierces deja connues et trackees (utiliser les issues du depot)
