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 :

  1. NE PAS créer un ticket GitHub public

  2. Rapport de sécurité par e-mail à: amrnetdashboard@gmail.com

  3. 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 :

Support de la version

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:

  1. Détection : Equipe de sécurité des alertes automatisées de surveillance

  2. Évaluation : Déterminer la sévérité et la portée de l’incident

  3. Contenu : Isoler les systèmes affectés si nécessaire

  4. Enquête : Analyser les logs et déterminer la cause racine

  5. Récupération : Restaurer les opérations normales

  6. 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 :