Security
Architecture de sécurité de l'application mobile YaniPay : authentification, stockage sécurisé, protection des données et conformité.
Overview
La sécurité est au cœur de YaniPay. En tant qu'application fintech manipulant des données financières sensibles, nous appliquons les standards de sécurité les plus élevés, conformes aux réglementations ACPR, RGPD et PSD2.
Certifications
YaniPay est conçu pour être conforme PCI-DSS, SOC 2 Type II et ISO 27001.
Security Layers
L'application implémente une architecture de sécurité en couches.
Authentication
- Biometric (Face ID/Touch ID)
- JWT tokens
- 2FA TOTP
- Session management
Storage
- Keychain/Keystore
- AES-256 encryption
- Secure enclave
- No plaintext secrets
Network
- TLS 1.3
- Certificate pinning
- Request signing
- Timeout policies
Application
- Code obfuscation
- Root/jailbreak detection
- Debug detection
- Tamper protection
Authentication
Mécanismes d'authentification multi-niveaux.
// Multi-factor authentication flow
const authenticationFlow = {
// Level 1: Primary authentication
primary: {
methods: ['email_password', 'oauth', 'magic_link'],
requirements: ['valid_credentials', 'verified_email'],
},
// Level 2: Second factor (if enabled)
secondary: {
methods: ['totp', 'sms', 'email'],
requirements: ['2fa_enabled', 'valid_code'],
},
// Level 3: Biometric (for sensitive actions)
biometric: {
methods: ['face_id', 'touch_id', 'fingerprint'],
requiredFor: ['view_card_details', 'send_money', 'change_settings'],
},
// Session management
session: {
accessTokenTTL: 15 * 60, // 15 minutes
refreshTokenTTL: 7 * 24 * 60 * 60, // 7 days
maxConcurrentSessions: 5,
autoLogoutInactivity: 5 * 60, // 5 minutes for financial apps
},
};
// Token refresh strategy
async function refreshTokenIfNeeded() {
const { sessionExpiresAt } = useAuthStore.getState();
// Refresh 5 minutes before expiry
const shouldRefresh = sessionExpiresAt &&
Date.now() > sessionExpiresAt - 5 * 60 * 1000;
if (shouldRefresh) {
await authStore.refreshSession();
}
}Data Protection
Protection des données sensibles au repos et en transit.
// Data classification and handling
const dataClassification = {
CRITICAL: {
examples: ['access_tokens', 'refresh_tokens', 'pin_codes', 'card_cvv'],
storage: 'secure_enclave',
encryption: 'hardware_backed',
retention: 'session_only',
logging: 'never',
},
SENSITIVE: {
examples: ['email', 'phone', 'full_name', 'address', 'transaction_history'],
storage: 'encrypted_keychain',
encryption: 'aes_256_gcm',
retention: 'until_logout',
logging: 'masked',
},
INTERNAL: {
examples: ['user_preferences', 'app_settings', 'feature_flags'],
storage: 'encrypted_async_storage',
encryption: 'optional',
retention: 'persistent',
logging: 'allowed',
},
PUBLIC: {
examples: ['app_version', 'device_type', 'language'],
storage: 'async_storage',
encryption: 'none',
retention: 'persistent',
logging: 'allowed',
},
};
// Data masking for logs
function maskSensitiveData(data: Record<string, unknown>): Record<string, unknown> {
const sensitiveFields = ['password', 'pin', 'cvv', 'cardNumber', 'token'];
return Object.fromEntries(
Object.entries(data).map(([key, value]) => {
if (sensitiveFields.some(field => key.toLowerCase().includes(field))) {
return [key, '***MASKED***'];
}
if (key === 'email' && typeof value === 'string') {
const [local, domain] = value.split('@');
return [key, `${local[0]}***@${domain}`];
}
return [key, value];
})
);
}Network Security
Sécurisation des communications réseau.
// SSL/TLS Configuration
const networkSecurityConfig = {
// Minimum TLS version
minTLSVersion: 'TLSv1.3',
// Certificate pinning
pinning: {
enabled: true,
pins: [
'sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', // Primary
'sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=', // Backup
],
includeSubdomains: true,
},
// Request timeout policies
timeouts: {
connect: 10000, // 10s
read: 30000, // 30s
write: 30000, // 30s
},
};
// Request signing for API calls
async function signRequest(request: AxiosRequestConfig): Promise<AxiosRequestConfig> {
const timestamp = Date.now();
const nonce = await generateRandomNonce();
const body = request.data ? JSON.stringify(request.data) : '';
// Create signature
const signaturePayload = `${request.method}|${request.url}|${timestamp}|${nonce}|${body}`;
const signature = await hmacSHA256(signaturePayload, API_SECRET);
return {
...request,
headers: {
...request.headers,
'X-Timestamp': timestamp.toString(),
'X-Nonce': nonce,
'X-Signature': signature,
},
};
}
// Detect and handle man-in-the-middle attacks
apiClient.interceptors.response.use(
response => response,
error => {
if (error.code === 'CERTIFICATE_VERIFY_FAILED') {
// Potential MITM attack
logSecurityEvent('certificate_validation_failed', {
url: error.config?.url,
error: error.message,
});
// Force logout and clear all data
forceSecurityLogout();
}
return Promise.reject(error);
}
);Compliance
Conformité réglementaire et audits de sécurité.
| Réglementation | Domaine | Statut |
|---|---|---|
| RGPD | Protection des données | Conforme |
| PSD2 | Paiements | Conforme |
| PCI-DSS | Cartes de paiement | En cours |
| SOC 2 Type II | Sécurité opérationnelle | Prévu Q3 |
Mises à jour Sécurité 2026 Mis à jour
Commit 2fed86e0 — patches via pnpm.overrides : effect, hono, axios, tar, ajv, minimatch, yaml, brace-expansion, picomatch, @xmldom/xmldom et plus. Sans breaking changes.
Commit f220a81b (T19-T21) — Validation Zod sur toutes les routes sensibles. Rate limiting : authRateLimit (5 req/15min), strictRateLimit (10 req/min). IBAN masqué dans les réponses API (4 derniers chiffres uniquement).
Commit 465f4216 (T17-T18) — Traçabilité réglementaire complète sur toutes les actions sensibles (KYC, paiements, cartes, connexions). Rétention 5 ans conforme Article L.561-12 du Code monétaire et financier.
Last updated: 2026-04-09