La plateforme Veille Platform intègre la sécurité dès la conception (Security by Design) avec plusieurs couches de protection.
┌─────────────────────────────────────────────────────────┐
│ Frontend (Admin) │
│ Next.js - Zone protégée │
└────────────────────────┬────────────────────────────────┘
│ HTTPS + JWT
▼
┌─────────────────────────────────────────────────────────┐
│ API Interne (Fastify) │
│ Zones: auth, items, stories │
│ Rate limiting, validation, audit logs │
└───────────┬─────────────────────────────────┬────────────┘
│ │
▼ ▼
┌───────────────────────┐ ┌─────────────────────────┐
│ Public API (lecture) │ │ Worker (jobs async) │
│ Endpoints publics │ │ BullMQ + Redis │
│ Rate limiting strict │ │ Validation SSRF │
└───────────────────────┘ └─────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────┐
│ Base de données │
│ PostgreSQL avec RLS (optionnel) │
└─────────────────────────────────────────────────────────┘
| Zone | Accès | Protection |
|---|---|---|
| Admin | Utilisateurs authentifiés | JWT, rôles, audit |
| API Interne | Services internes + Admin | JWT, rate limiting |
| Public API | Tout le monde | Rate limiting, validation |
| Worker | Services internes uniquement | Validation, sandbox |
Protection: Prisma ORM avec requêtes paramétrées
// ✅ Sécurisé - Paramètres liés
const user = await prisma.user.findUnique({
where: { id: userId }
});
// ❌ Non sécurisé - Jamais fait dans le codebase
const user = await prisma.$queryRaw`SELECT * FROM users WHERE id = ${id}`;Protection:
- Échappement automatique par React
- CSP headers stricts
- Validation Zod sur les entrées
Protection:
- JWT dans headers Authorization (pas de cookies)
- CORS configuré avec origines explicites
- SameSite cookies si utilisés
Protection:
// Dans packages/security/src/ssrf.ts
const BLOCKED_IP_RANGES = [
/^127\./, // localhost
/^10\./, // Private
/^172\.(1[6-9]|2[0-9]|3[0-1])\./, // Private
/^192\.168\./, // Private
/^169\.254\./, // AWS metadata
/^::1$/, // IPv6 localhost
];
export async function checkSSRF(url: string, options: SSRFCheckOptions) {
// Validation du hostname
// Vérification DNS reverse
// Contrôle du port
// Whitelist de domaines optionnelle
}Protection:
// Validation stricte
const ALLOWED_MIME_TYPES = [
'image/jpeg',
'image/png',
'image/gif',
'image/webp',
'application/pdf',
];
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
export function validateFile(file: File) {
// Type MIME vérifié
// Taille vérifiée
// Extension vérifiée
// Scan de contenu (futur)
}Protection:
// Configuration par endpoint
const RATE_LIMITS = {
DEFAULT: { window: 60, max: 100 },
API_KEY: { window: 60, max: 1000 },
AUTH: { window: 900, max: 5 }, // 5 tentatives / 15min
IMPORT: { window: 3600, max: 10 },
};Protection:
- UUIDs non-devinables pour les ressources
- Messages d'erreur génériques
- Rate limiting sur les authentifications
Protection:
- Public API: Uniquement contenus publiés -过滤 des champs internes (passwordHash, tokens, etc.)
- Audit logs de tous les accès
# .env (jamais commité)
DATABASE_URL="postgresql://..."
AUTH_SECRET="min-32-chars-secret"
OPENAI_API_KEY="sk-..."
# Ne JAMAIS faire
git add .env- JWT secrets: Rotation possible via admin
- API keys: Régénération dans settings
- Database: Rotation via admin PostgreSQL
interface JWTPayload {
sub: string; // User ID
email: string;
workspaceId: string;
role: UserRole;
iat: number; // Issued at
exp: number; // Expiration
}| Rôle | CRUD Items | CRUD Stories | Manage Sources | Admin |
|---|---|---|---|---|
| VIEWER | Read | Read | - | - |
| CURATOR | Read, Update | Read | - | - |
| EDITOR | Full | Full | - | - |
| ADMIN | Full | Full | Full | Partial |
| OWNER | Full | Full | Full | Full |
Toutes les actions sensibles sont journalisées:
await prisma.auditLog.create({
data: {
userId: user.id,
action: 'DELETE',
targetType: 'item',
targetId: item.id,
workspaceId: workspace.id,
metadata: { reason: 'spam' },
ipAddress: request.ip,
userAgent: request.headers['user-agent'],
},
});- Pas de 2FA obligatoire - Recommandé pour production
- Pas de WAF - À ajouter (Cloudflare, etc.)
- Pas de Encryption at Rest - À configurer PostgreSQL
- Pas de Backup automatisé - À mettre en place
-
Infrastructure
- Utiliser un managed PostgreSQL (Neon, Supabase, etc.)
- Redis managé pour le worker
- CDN pour les assets statiques
- WAF (Cloudflare, AWS WAF)
-
Monitoring
- Logs centralisés (Datadog, Sentry)
- Alertes de sécurité
- Dashboard de monitoring
-
Compliance
- RGPD: Data retention policy
- Cookies consent
- Privacy policy
Pour signaler une vulnérabilité: security@platform.io