Deployment
Sécurité
Guide de sécurité pour le déploiement de Company Manager.
Sécurité
Guide complet des mesures de sécurité pour le déploiement de Company Manager.
Configuration de Base
HTTPS
# Configuration Nginx SSL
server {
listen 443 ssl http2;
server_name app.company-manager.com;
ssl_certificate /etc/letsencrypt/live/app.company-manager.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.company-manager.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# HSTS
add_header Strict-Transport-Security "max-age=31536000" always;
}Headers de Sécurité
// Configuration des headers
const securityHeaders = {
'Content-Security-Policy': `
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
`,
'X-Frame-Options': 'DENY',
'X-Content-Type-Options': 'nosniff',
'Referrer-Policy': 'strict-origin-when-cross-origin',
'Permissions-Policy': 'camera=(), microphone=(), geolocation=()',
};Authentification
Configuration JWT
// Configuration des tokens
const jwtConfig = {
secret: process.env.JWT_SECRET,
expiresIn: '1d',
algorithm: 'HS256',
issuer: 'company-manager',
};
// Validation des tokens
const validateToken = async (token: string) => {
try {
const decoded = jwt.verify(token, jwtConfig.secret, {
algorithms: [jwtConfig.algorithm],
issuer: jwtConfig.issuer,
});
return decoded;
} catch (error) {
throw new TokenValidationError(error.message);
}
};Rate Limiting
// Configuration du rate limiting
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limite par IP
message: 'Trop de requêtes, veuillez réessayer plus tard.',
standardHeaders: true,
legacyHeaders: false,
});Base de Données
Chiffrement des Données
// Service de chiffrement
class EncryptionService {
private readonly algorithm = 'aes-256-gcm';
private readonly key = Buffer.from(process.env.ENCRYPTION_KEY!, 'hex');
encrypt(text: string): EncryptedData {
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);
const encrypted = Buffer.concat([
cipher.update(text, 'utf8'),
cipher.final(),
]);
const tag = cipher.getAuthTag();
return {
encrypted: encrypted.toString('hex'),
iv: iv.toString('hex'),
tag: tag.toString('hex'),
};
}
decrypt(data: EncryptedData): string {
const decipher = crypto.createDecipheriv(
this.algorithm,
this.key,
Buffer.from(data.iv, 'hex')
);
decipher.setAuthTag(Buffer.from(data.tag, 'hex'));
return Buffer.concat([
decipher.update(Buffer.from(data.encrypted, 'hex')),
decipher.final(),
]).toString('utf8');
}
}Sécurité PostgreSQL
-- Configuration PostgreSQL
ALTER SYSTEM SET ssl = on;
ALTER SYSTEM SET ssl_cert_file = 'server.crt';
ALTER SYSTEM SET ssl_key_file = 'server.key';
-- Permissions restrictives
REVOKE ALL ON ALL TABLES IN SCHEMA public FROM PUBLIC;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;Monitoring de Sécurité
Logs de Sécurité
// Configuration des logs de sécurité
const securityLogger = winston.createLogger({
level: 'info',
format: winston.format.json(),
defaultMeta: { service: 'security' },
transports: [
new winston.transports.File({
filename: 'logs/security.log',
level: 'info',
}),
],
});
// Logging des événements de sécurité
const logSecurityEvent = (
event: string,
details: Record<string, unknown>
) => {
securityLogger.info(event, {
timestamp: new Date().toISOString(),
...details,
});
};Alertes
// Service d'alertes
class SecurityAlertService {
async sendAlert(
level: 'high' | 'medium' | 'low',
message: string,
details: any
) {
await prisma.securityAlert.create({
data: {
level,
message,
details,
timestamp: new Date(),
},
});
if (level === 'high') {
await this.notifySecurityTeam(message, details);
}
}
private async notifySecurityTeam(
message: string,
details: any
) {
// Notification par email, Slack, etc.
}
}Protection des Données
Masquage des Données Sensibles
// Middleware de masquage
const maskSensitiveData = (data: any): any => {
const sensitiveFields = ['password', 'credit_card', 'ssn'];
return Object.entries(data).reduce(
(acc, [key, value]) => ({
...acc,
[key]: sensitiveFields.includes(key)
? '********'
: value,
}),
{}
);
};Audit Trail
// Service d'audit
class AuditService {
async logAction(
userId: string,
action: string,
resource: string,
details: any
) {
await prisma.auditLog.create({
data: {
userId,
action,
resource,
details,
ipAddress: getCurrentIp(),
userAgent: getCurrentUserAgent(),
timestamp: new Date(),
},
});
}
async getAuditTrail(
filters: AuditFilters
): Promise<AuditLog[]> {
return prisma.auditLog.findMany({
where: filters,
orderBy: { timestamp: 'desc' },
});
}
}Bonnes Pratiques
Gestion des Secrets
// Service de gestion des secrets
class SecretManager {
private readonly vault: Vault;
constructor() {
this.vault = new Vault({
token: process.env.VAULT_TOKEN,
endpoint: process.env.VAULT_URL,
});
}
async getSecret(path: string): Promise<string> {
const { data } = await this.vault.read(`secret/data/${path}`);
return data.data;
}
async rotateSecret(path: string): Promise<void> {
const newSecret = crypto.randomBytes(32).toString('hex');
await this.vault.write(`secret/data/${path}`, {
data: { value: newSecret },
});
}
}Sécurité des Dépendances
# Audit des dépendances
bun audit
# Mise à jour des dépendances vulnérables
bun update --security
# Vérification des licences
npx license-checker --summaryTests de Sécurité
Tests Automatisés
// Tests de sécurité
describe('Security', () => {
it('should hash passwords correctly', async () => {
const password = 'test123';
const hash = await hashPassword(password);
expect(hash).not.toBe(password);
expect(await verifyPassword(password, hash)).toBe(true);
});
it('should prevent SQL injection', async () => {
const maliciousInput = "'; DROP TABLE users; --";
await expect(
userService.findByName(maliciousInput)
).rejects.toThrow();
});
});Scan de Vulnérabilités
# GitHub Actions security scan
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run OWASP ZAP scan
uses: zaproxy/action-full-scan@v0.4.0
- name: Run Snyk scan
uses: snyk/actions/node@master