Compétence 11 : Intégrité des Données¶
Vérifier l'intégrité des données traitées en s'appuyant sur les techniques de vérification de données et dans le respect des normes de conformité et de sécurité afin de s'assurer que la donnée n'a pas été corrompue et de prévenir ainsi les dysfonctionnements du logiciel.
Observable 11.1 : Vérifications pour l'Intégrité et la Stabilité¶
Validation des Messages Réseau¶
Pattern from_bytes() avec Validation¶
Chaque structure du protocole implémente une validation stricte lors du parsing.
Fichier : src/common/protocol/Protocol.hpp
static std::optional<LoginMessage> from_bytes(const void* buf, size_t buf_len) {
// 1. Vérification nullptr
if (buf == nullptr) return std::nullopt;
// 2. Vérification taille minimale
if (buf_len < MAX_USERNAME_LEN + MAX_PASSWORD_LEN) return std::nullopt;
LoginMessage msg;
auto* ptr = static_cast<const uint8_t*>(buf);
// 3. Copie sécurisée avec limites
std::memcpy(msg.username, ptr, MAX_USERNAME_LEN);
std::memcpy(msg.password, ptr + MAX_USERNAME_LEN, MAX_PASSWORD_LEN);
// 4. Null-termination forcée
msg.username[MAX_USERNAME_LEN - 1] = '\0';
msg.password[MAX_PASSWORD_LEN - 1] = '\0';
return msg;
}
Constantes de Limites¶
static constexpr size_t MAX_USERNAME_LEN = 32;
static constexpr size_t MAX_PASSWORD_LEN = 64;
static constexpr size_t MAX_EMAIL_LEN = 255; // RFC 5321
static constexpr size_t MAX_MESSAGE_LEN = 500;
Validation des Headers TCP¶
Fichier : src/server/infrastructure/adapters/in/network/TCPAuthServer.cpp:152-166
while (_accumulator.size() >= Header::WIRE_SIZE) {
// 1. Parser le header
auto headOpt = Header::from_bytes(_accumulator.data(), _accumulator.size());
if (!headOpt) break; // Header invalide
Header head = *headOpt;
// 2. Vérifier que le message complet est disponible
size_t totalSize = Header::WIRE_SIZE + head.payload_size;
if (_accumulator.size() < totalSize) break; // Attendre plus de données
// 3. Traiter le message complet
handle_command(head);
// 4. Retirer les données traitées
_accumulator.erase(_accumulator.begin(), _accumulator.begin() + totalSize);
}
Validation UDP avec Numéros de Séquence¶
struct UDPHeader {
uint16_t type;
uint16_t sequence_num; // Pour détection replay/réordonnancement
uint64_t timestamp; // Pour fraîcheur des données
};
Vérifications possibles : - Rejet des paquets trop anciens (timestamp) - Détection des paquets dupliqués (sequence_num) - Réordonnancement si nécessaire
Validation de la Compression¶
Fichier : src/common/compression/Compression.hpp:67-90
inline std::optional<std::vector<uint8_t>> decompress(
const uint8_t* src, size_t srcSize, size_t originalSize
) {
// 1. Vérification des paramètres
if (srcSize == 0 || src == nullptr || originalSize == 0) {
return std::nullopt;
}
// 2. Limite de taille pour éviter DoS
if (originalSize > MAX_UNCOMPRESSED_SIZE) {
return std::nullopt;
}
std::vector<uint8_t> decompressed(originalSize);
// 3. Décompression avec vérification
int decompressedSize = LZ4_decompress_safe(
reinterpret_cast<const char*>(src),
reinterpret_cast<char*>(decompressed.data()),
static_cast<int>(srcSize),
static_cast<int>(originalSize)
);
// 4. Vérification taille exacte
if (decompressedSize < 0 ||
static_cast<size_t>(decompressedSize) != originalSize) {
return std::nullopt; // Corruption détectée
}
return decompressed;
}
Validation des Entrées Utilisateur¶
Password Validation¶
Fichier : src/server/domain/value_objects/user/Password.cpp
void Password::validate(const std::string& password) {
if (password.length() < 6) {
throw exceptions::user::PasswordException(password);
}
// Critères supplémentaires possibles : caractères spéciaux, chiffres, etc.
}
Email Validation¶
// Vérification format basique (présence @)
bool isValidEmail(const std::string& email) {
auto at = email.find('@');
if (at == std::string::npos) return false;
if (at == 0 || at == email.length() - 1) return false;
return true;
}
Gestion des Erreurs TLS¶
Fichier : src/server/infrastructure/adapters/in/network/TCPAuthServer.cpp:926-930
sslSocket->async_handshake(
ssl::stream_base::server,
[networkLogger, clientEndpoint](boost::system::error_code hsError) {
if (hsError) {
networkLogger->warn("TLS handshake failed from {}: {}",
clientEndpoint.address().to_string(), hsError.message());
return; // Pas de session si handshake échoue
}
// Session créée uniquement après TLS réussi
}
);
Observable 11.2 : Moyens pour l'Intégrité et la Confidentialité¶
Chiffrement TLS 1.2+¶
Configuration Sécurisée¶
Fichier : src/server/infrastructure/adapters/in/network/TCPAuthServer.cpp:819-840
// Protocoles obsolètes désactivés
ssl::context::no_sslv2 |
ssl::context::no_sslv3 |
ssl::context::no_tlsv1 |
ssl::context::no_tlsv1_1
// TLS 1.2 minimum
SSL_CTX_set_min_proto_version(_sslContext.native_handle(), TLS1_2_VERSION);
// Cipher suites avec Forward Secrecy + AEAD
"ECDHE-ECDSA-AES256-GCM-SHA384:"
"ECDHE-RSA-AES256-GCM-SHA384:"
"ECDHE-ECDSA-AES128-GCM-SHA256:"
"ECDHE-RSA-AES128-GCM-SHA256:"
"ECDHE-ECDSA-CHACHA20-POLY1305:"
"ECDHE-RSA-CHACHA20-POLY1305"
Garanties¶
| Propriété | Mécanisme |
|---|---|
| Confidentialité | AES-256-GCM / ChaCha20-Poly1305 |
| Intégrité | AEAD (Authenticated Encryption) |
| Forward Secrecy | ECDHE (clés éphémères) |
| Authentification serveur | Certificats X.509 |
Hachage des Mots de Passe¶
Fichier : src/server/domain/value_objects/user/PasswordUtils.cpp
std::string hashPassword(std::string password) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char*>(password.c_str()),
password.length(), hash);
std::stringstream ss;
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
ss << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(hash[i]);
}
return ss.str(); // 64 caractères hex
}
Garanties : - Mot de passe jamais stocké en clair - Hash SHA-256 (256 bits) irréversible - Stockage uniquement du hash en base MongoDB
Génération de Tokens Sécurisés¶
Vulnérabilité corrigée : CWE-338 (Weak PRNG)
// AVANT (prédictible)
std::mt19937_64 rng; // Mersenne Twister
// APRÈS (CSPRNG)
SessionToken generateToken() {
unsigned char buffer[32];
RAND_bytes(buffer, 32); // OpenSSL CSPRNG (FIPS 140-2)
// Conversion hex -> 64 caractères
}
Propriétés des tokens : - 256 bits d'entropie - Cryptographiquement imprévisibles - Uniques (collision négligeable)
Heartbeat et Timeout Anti-DoS¶
Fichier : src/server/infrastructure/adapters/in/network/TCPAuthServer.cpp:22-23
static constexpr int CLIENT_TIMEOUT_MS = 5000; // 5 secondes
static constexpr int TIMEOUT_CHECK_INTERVAL_MS = 1000;
Implémentation :
void Session::scheduleTimeoutCheck() {
_timeoutTimer.expires_after(std::chrono::milliseconds(TIMEOUT_CHECK_INTERVAL_MS));
_timeoutTimer.async_wait([this](boost::system::error_code ec) {
if (ec) return;
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - _lastActivity
).count();
if (elapsed > CLIENT_TIMEOUT_MS) {
// Fermeture session inactive
closeSession();
return;
}
scheduleTimeoutCheck(); // Reschedule
});
}
Protection : Empêche les connexions fantômes et limite l'épuisement des ressources.
Byte Order Réseau (Endianness)¶
Fichier : src/common/protocol/Protocol.hpp:17-19
inline uint64_t swap64(uint64_t v) { return __builtin_bswap64(v); }
inline uint32_t swap32(uint32_t v) { return __builtin_bswap32(v); }
inline uint16_t swap16(uint16_t v) { return __builtin_bswap16(v); }
Usage :
void to_bytes(void* buf) const {
uint16_t net_x = swap16(x); // Host -> Network (big-endian)
std::memcpy(buf, &net_x, 2);
}
static auto from_bytes(const void* buf, size_t len) {
uint16_t net_x;
std::memcpy(&net_x, buf, 2);
x = swap16(net_x); // Network -> Host
}
Garantie : Interopérabilité entre machines little-endian et big-endian.
Tableau Récapitulatif des Protections¶
| Donnée | Menace | Protection | Fichier |
|---|---|---|---|
| Credentials transit | Interception | TLS 1.2+ | TCPAuthServer.cpp |
| Passwords stockés | Vol base | SHA-256 hash | PasswordUtils.cpp |
| Session tokens | Prédiction | CSPRNG 256-bit | SessionManager.hpp |
| Messages UDP | Rejeu | Sequence numbers | Protocol.hpp |
| Données compressées | Corruption | Vérification taille | Compression.hpp |
| Connexions | DoS | Timeout 5s | TCPAuthServer.cpp |
| Entrées utilisateur | Injection | Validation stricte | from_bytes() |
Conformité Standards¶
| Standard | Exigence | Implémenté |
|---|---|---|
| OWASP A02 | Cryptographic Failures | TLS 1.2+, RAND_bytes |
| OWASP A03 | Injection | Validation binaire |
| OWASP A07 | Auth Failures | SHA-256, sessions |
| CWE-319 | Cleartext Transmission | TLS obligatoire |
| CWE-338 | Weak PRNG | OpenSSL CSPRNG |
| NIST 800-52 | TLS Guidelines | TLS 1.2+, ECDHE, AEAD |
Conclusion¶
R-Type garantit l'intégrité et la confidentialité des données via :
- Validation stricte :
from_bytes()avec vérification taille et null-termination - Chiffrement transport : TLS 1.2+ avec Forward Secrecy
- Protection stockage : Hachage SHA-256 des mots de passe
- Tokens sécurisés : CSPRNG OpenSSL (256 bits)
- Protection réseau : Sequence numbers, timestamps, timeouts
Ces mécanismes assurent la stabilité du logiciel et la protection des données utilisateur.