Guide de sécurité¶
AMRnet met en œuvre des mesures de sécurité complètes pour protéger les données des utilisateurs et assurer l’intégrité des informations de surveillance de la résistance antimicrobienne. Ce guide couvre les politiques de sécurité, les meilleures pratiques et les détails de l’implémentation.
Politique de sécurité¶
AMRnet suit les pratiques de sécurité standard de l’industrie pour les applications Web qui traitent les soins de santé sensibles et les données de recherche.
Rapports de vulnérabilité¶
🚨 Processus de divulgation responsable
Si vous découvrez une vulnérabilité de sécurité, veuillez suivre ces étapes :
NE PAS créer un ticket GitHub public
Rapport de sécurité par e-mail à: amrnetdashboard@gmail.com
Inclure des informations détaillées : - Description de la vulnérabilité - Étapes pour reproduire le problème - Évaluation de l’impact potentiel - Corrections suggérées (si disponible)
Ligne de réponse :
24 heures : Reconnaissance initiale
72 heures : Évaluation préliminaire et classification de la gravité
7 jours: Réponse détaillée avec fil fixe
30 jours : Résolution cible pour les vulnérabilités critiques
Versions prises en charge¶
Des mises à jour de sécurité sont fournies pour :
Version |
Supporté |
|---|---|
1.1.x |
✅ Oui |
1.0.x |
✅ Oui |
< 1.0 |
❌ Non |
Sécurité de l’application¶
AMRnet implémente plusieurs couches de contrôles de sécurité :
Sécurité de l’environnement¶
Protection des variables d’environnement :
# Never commit sensitive environment variables
# Use .env.example as template, create .env locally
# Production secrets management
NODE_ENV=production
MONGODB_URI=mongodb+srv://[REDACTED]
SESSION_SECRET=[GENERATED_SECRET]
# Security headers
ENABLE_SECURITY_HEADERS=true
CORS_ORIGIN=https://amrnet.org
Exemple de Configuration Sécurisée :
// config/security.js
const securityConfig = {
// HTTPS enforcement
httpsOnly: process.env.NODE_ENV === 'production',
// Security headers
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
imgSrc: ["'self'", "data:", "https:"],
scriptSrc: ["'self'"]
}
},
// Rate limiting
rateLimit: {
windowMs: 15 * 60 * 1000, // 15 minutes
max: 1000 // limit each IP to 1000 requests per windowMs
}
};
Sécurité de la base de données¶
Configuration de sécurité MongoDB :
// Secure MongoDB connection
const mongoOptions = {
useNewUrlParser: true,
useUnifiedTopology: true,
// Authentication
authSource: 'admin',
// SSL/TLS
ssl: true,
sslValidate: true,
// Connection limits
maxPoolSize: 10,
minPoolSize: 5,
// Timeouts
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
// Security options
bufferMaxEntries: 0,
bufferCommands: false
};
Assainissement des données :
const sanitize = require('mongo-sanitize');
const validator = require('validator');
// Input sanitization middleware
const sanitizeInput = (req, res, next) => {
// Sanitize against NoSQL injection
req.body = sanitize(req.body);
req.query = sanitize(req.query);
req.params = sanitize(req.params);
// Additional validation
Object.keys(req.query).forEach(key => {
if (typeof req.query[key] === 'string') {
req.query[key] = validator.escape(req.query[key]);
}
});
next();
};
Sécurité de l’API¶
Authentification et Autorisation :
const jwt = require('jsonwebtoken');
const rateLimit = require('express-rate-limit');
// API rate limiting
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 1000, // limit each IP to 1000 requests per windowMs
message: 'Too many requests from this IP',
standardHeaders: true,
legacyHeaders: false,
});
// JWT authentication for protected endpoints
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.sendStatus(401);
}
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
};
Configuration CORS :
const cors = require('cors');
const corsOptions = {
origin: function (origin, callback) {
const allowedOrigins = [
'https://amrnet.org',
'https://www.amrnet.org',
process.env.NODE_ENV === 'development' && 'http://localhost:3000'
].filter(Boolean);
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
optionsSuccessStatus: 200
};
Sécurité du frontend¶
Politique de sécurité du contenu :
<!-- Security headers in HTML -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https:;">
Prévention XSS :
import DOMPurify from 'dompurify';
// Sanitize user input before rendering
const SafeHTML = ({ content }) => {
const cleanHTML = DOMPurify.sanitize(content);
return <div dangerouslySetInnerHTML={{ __html: cleanHTML }} />;
};
// Input validation
const validateInput = (input) => {
if (typeof input !== 'string') return false;
if (input.length > 1000) return false;
// Check for malicious patterns
const maliciousPatterns = [
/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
/javascript:/gi,
/on\w+\s*=/gi
];
return !maliciousPatterns.some(pattern => pattern.test(input));
};
Confidentialité des données¶
AMRnet met en œuvre les principes de confidentialité par conception pour le traitement des données de surveillance:
Classification des données¶
Données publiques: - Statistiques de surveillance agrégées - Données de prévalence au niveau du pays - Jeux de données de recherche disponibles publiquement
Données restreintes: - Identifiants individuels d’échantillons (lorsqu’ils sont présents) - Coordonnées géographiques détaillées - Données de recherche non publiées
Données interdites: - Informations personnelles sur la santé (IPP) - Identifiants du patient - Détails cliniques au-delà des modèles de résistance
Contrôles de confidentialité¶
Minimisation des données:
// Example: Remove sensitive fields before transmission
const sanitizeDataForPublic = (data) => {
return data.map(record => ({
// Include only necessary fields
country: record.COUNTRY_ONLY,
year: record.YEAR,
genotype: record.GENOTYPE,
resistance: record.RESISTANCE_PROFILE,
// Exclude: individual IDs, precise coordinates, etc.
}));
};
Anonymisation:
// Geographic aggregation for privacy
const aggregateByRegion = (data) => {
const aggregated = {};
data.forEach(record => {
const region = getRegionFromCountry(record.country);
if (!aggregated[region]) {
aggregated[region] = {
count: 0,
resistanceProfiles: {}
};
}
aggregated[region].count++;
// Aggregate resistance data without individual records
});
return aggregated;
};
Développement sécurisé¶
Pratiques de sécurité pour le développement et le déploiement :
Sécurité du code¶
Gestion des dépendances :
# Regular security audits
npm audit
# Update vulnerable dependencies
npm audit fix
# Use lock files to prevent supply chain attacks
npm ci # Use exact versions from package-lock.json
Réduction de la sécurité:
# ESLint security plugin
npm install --save-dev eslint-plugin-security
# .eslintrc.js
module.exports = {
plugins: ['security'],
extends: ['plugin:security/recommended'],
rules: {
'security/detect-object-injection': 'error',
'security/detect-non-literal-regexp': 'error',
'security/detect-unsafe-regex': 'error'
}
};
Sécurité Git¶
Pratiques de sécurisation des dépôts :
# Git hooks for security
# pre-commit hook
#!/bin/sh
# Check for secrets in commits
git diff --cached --name-only | xargs grep -l "password\|secret\|key\|token" && {
echo "Potential secret detected! Commit aborted."
exit 1
}
# Run security linting
npm run lint:security
Gestion des Secrets :
# .gitignore - Never commit sensitive files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Security credentials
*.pem
*.key
*.crt
# Database dumps
*.sql
*.dump
Sécurité de déploiement¶
Configurations de sécurité pour le déploiement de production :
Sécurité du serveur¶
En-têtes de sécurité :
const helmet = require('helmet');
app.use(helmet({
// Content Security Policy
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
imgSrc: ["'self'", "data:", "https:"],
scriptSrc: ["'self'"],
connectSrc: ["'self'", "https://api.amrnet.org"]
}
},
// Other security headers
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
frameguard: { action: 'deny' },
noSniff: true,
xssFilter: true,
referrerPolicy: { policy: 'same-origin' }
}));
Sécurité des infrastructures¶
Configuration HTTPS:
# Nginx SSL configuration
server {
listen 443 ssl http2;
server_name amrnet.org www.amrnet.org;
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
ssl_prefer_server_ciphers off;
# Security headers
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
}
Surveillance et réponse au ticket¶
Surveillance continue de la sécurité et procédures de réponse aux incidents :
Surveillance de sécurité¶
Journalisation et Alerte :
const winston = require('winston');
// Security event logging
const securityLogger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'logs/security.log' })
]
});
// Failed authentication attempts
const logFailedAuth = (req, ip, reason) => {
securityLogger.warn('Failed authentication attempt', {
ip: ip,
userAgent: req.get('User-Agent'),
reason: reason,
timestamp: new Date().toISOString()
});
};
Détection d’intrusion :
// Suspicious activity detection
const suspiciousActivityDetector = {
failedAttempts: new Map(),
checkFailedLogins: (ip) => {
const attempts = this.failedAttempts.get(ip) || 0;
this.failedAttempts.set(ip, attempts + 1);
if (attempts > 5) {
// Trigger security alert
this.triggerSecurityAlert(`Multiple failed login attempts from ${ip}`);
}
},
triggerSecurityAlert: (message) => {
securityLogger.error('Security Alert', { message });
// Send notification to security team
}
};
Réponse du Ticket¶
Procédures de réponse:
Détection : Equipe de sécurité des alertes automatisées de surveillance
Évaluation : Déterminer la sévérité et la portée de l’incident
Contenu : Isoler les systèmes affectés si nécessaire
Enquête : Analyser les logs et déterminer la cause racine
Récupération : Restaurer les opérations normales
Leçons apprises : Mettre à jour les mesures de sécurité basées sur les conclusions
Test de sécurité¶
Des tests de sécurité réguliers garantissent une protection continue :
Tests automatisés¶
Suite de test de sécurité :
// __tests__/security.test.js
describe('Security Tests', () => {
it('should prevent SQL injection in API endpoints', async () => {
const maliciousInput = "'; DROP TABLE users; --";
const response = await request(app)
.get(`/api/organisms?country=${maliciousInput}`)
.expect(400);
expect(response.body.error).toContain('Invalid input');
});
it('should enforce rate limiting', async () => {
const requests = Array(1001).fill().map(() =>
request(app).get('/api/organisms')
);
const responses = await Promise.all(requests);
const rateLimited = responses.filter(r => r.status === 429);
expect(rateLimited.length).toBeGreaterThan(0);
});
});
Tests de pénétration¶
Évaluations de sécurité régulières :
Analyses de vulnérabilité trimestrielles
Examen annuel de la pénétration par des sociétés de sécurité tierces
Surveillance continue de la sécurité
Programme de récompenses de bugs pour la divulgation responsable
Liste de contrôle des meilleures pratiques¶
Liste de contrôle de la sécurité du développement :
✅ Environment Security - [ ] Ne jamais livrer de secrets au contrôle de version - [ ] Utiliser une gestion des variables d’environnement sécurisé - [ ] Implémenter une rotation secrète appropriée
✅ Sécurité de l’application - [ ] Validation et assainissement de l’entrée - [ ] Encodage de sortie pour empêcher XSS - [ ] prévention d’injection SQL - [ ] Authentification et autorisation
✅ Infrastructure Security - [ ] Application HTTPS - [ ] Implémentation d’en-têtes de sécurité - [ ] Mises à jour régulières des dépendances - [ ] Contrôles d’accès à la base de données
✅ Surveillance et réponse - [ ] Journalisation d’événements de sécurité - [ ] Systèmes de détection d’intrusion - [ ] Procédures de réponse d’incident - [ ] Évaluations de sécurité régulières
Coordonnées¶
Contact de l’équipe de sécurité :
Email: amrnetdashboard@gmail.com
Clé PGP : Disponible sur demande
Temps de réponse: 24 heures pour la réception initiale
Pour les questions de sécurité générale :
Discussions GitHub: https://github.com/amrnet/amrnet/discussions
Documentation : https://amrnet.readthedocs.io