~~NOTOC~~ ====== Scenarij 10.2: Konfiguracija TLS odjemalca ====== **Kategorija:** [[.:start|TLS/mTLS]] \\ **Kompleksnost:** ⭐⭐⭐ (Srednja) \\ **Predpogoji:** Shramba zaupanja, opcijski odjemalčev certifikat \\ **Predviden čas:** 15-20 minut ---- ===== Opis ===== Ta scenarij opisuje **konfiguracijo TLS odjemalca** za varne povezave s strežniki s postkvantnimi certifikati. **Naloge odjemalca:** * Validacija strežniškega certifikata * Konfiguracija shrambe zaupanja * TLS različica in šifrirni nabori * Opcijsko: Predstavitev odjemalčevega certifikata ---- ===== Potek dela ===== flowchart LR TRUST[Nalaganje shrambe zaupanja] --> CONNECT[Vzpostavitev povezave] CONNECT --> VERIFY[Preverjanje strežniškega certifikata] VERIFY --> CHAIN[Validacija verige] CHAIN --> REV[Preverjanje preklica] REV --> OK{Vse v redu?} OK -->|Da| DATA[Prenos podatkov] OK -->|Ne| ABORT[Prekinitev] style DATA fill:#e8f5e9 style ABORT fill:#ffebee ---- ===== Primer kode: HttpClient s prilagojeno shrambo zaupanja ===== using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using var ctx = PqCryptoContext.Initialize(); // Nalaganje prilagojene shrambe zaupanja var trustedCerts = new X509Certificate2Collection(); trustedCerts.Add(ctx.LoadCertificate("company-root-ca.crt.pem")); trustedCerts.Add(ctx.LoadCertificate("company-intermediate-ca.crt.pem")); // Konfiguracija HttpClientHandler var handler = new HttpClientHandler { // Prilagojena validacija strežniškega certifikata ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { // Najprej preverjanje standardnih napak if (errors == SslPolicyErrors.None) { return true; } // Pri UntrustedRoot: Uporaba prilagojene shrambe zaupanja if (errors == SslPolicyErrors.RemoteCertificateChainErrors) { var customChain = new X509Chain(); customChain.ChainPolicy.CustomTrustStore.AddRange(trustedCerts); customChain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; customChain.ChainPolicy.RevocationMode = X509RevocationMode.Online; customChain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; bool isValid = customChain.Build(cert); if (!isValid) { foreach (var status in customChain.ChainStatus) { Console.WriteLine($"Napaka verige: {status.StatusInformation}"); } } return isValid; } Console.WriteLine($"SSL napaka: {errors}"); return false; }, // TLS različica SslProtocols = SslProtocols.Tls13, // Preverjanje preklica CheckCertificateRevocationList = true }; using var httpClient = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(30) }; // Izvajanje zahteve var response = await httpClient.GetAsync("https://api.example.com/data"); Console.WriteLine($"Status: {response.StatusCode}"); ---- ===== Primer kode: TLS odjemalec s SocketsHttpHandler ===== // SocketsHttpHandler za več nadzora var socketsHandler = new SocketsHttpHandler { // Združevanje povezav PooledConnectionLifetime = TimeSpan.FromMinutes(15), PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2), MaxConnectionsPerServer = 10, // TLS konfiguracija SslOptions = new SslClientAuthenticationOptions { // Zahtevanje TLS 1.3 EnabledSslProtocols = SslProtocols.Tls13, // Ime strežnika za SNI TargetHost = "api.example.com", // Povratni klic za validacijo certifikata RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => { if (errors == SslPolicyErrors.None) return true; // Beleženje Console.WriteLine($"Certifikat: {certificate?.Subject}"); Console.WriteLine($"Napake: {errors}"); return false; // Stroga validacija }, // Aplikacijski protokoli (ALPN) ApplicationProtocols = new List { SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 } } }; using var client = new HttpClient(socketsHandler); ---- ===== Pripenjanje certifikata ===== public class CertificatePinningHandler : HttpClientHandler { private readonly HashSet _pinnedCertificates; public CertificatePinningHandler(params string[] pinnedThumbprints) { _pinnedCertificates = new HashSet( pinnedThumbprints, StringComparer.OrdinalIgnoreCase ); ServerCertificateCustomValidationCallback = ValidateServerCertificate; } private bool ValidateServerCertificate( HttpRequestMessage message, X509Certificate2? cert, X509Chain? chain, SslPolicyErrors errors) { if (cert == null) return false; // 1. Standardna validacija if (errors != SslPolicyErrors.None) { Console.WriteLine($"SSL napaka politike: {errors}"); return false; } // 2. Preverjanje pripetja (list ali vmesni) bool pinValid = false; // Preverjanje list certifikata if (_pinnedCertificates.Contains(cert.Thumbprint)) { pinValid = true; } // Iskanje po verigi if (!pinValid && chain != null) { foreach (var element in chain.ChainElements) { if (_pinnedCertificates.Contains(element.Certificate.Thumbprint)) { pinValid = true; break; } } } if (!pinValid) { Console.WriteLine($"Neujemanje pripetja certifikata: {cert.Thumbprint}"); } return pinValid; } } // Uporaba var pinnedHandler = new CertificatePinningHandler( "A1B2C3D4E5F6...", // Prstni odtis list certifikata "B2C3D4E5F6G7..." // Prstni odtis vmesnega certifikata (rezervno pripetje) ); using var client = new HttpClient(pinnedHandler); ---- ===== Upravljanje shrambe zaupanja ===== public class TrustStoreManager { private readonly X509Certificate2Collection _trustedRoots = new(); private readonly X509Certificate2Collection _trustedIntermediates = new(); public void AddTrustedRoot(string certPath) { var cert = new X509Certificate2(certPath); // Preverjanje ali je CA certifikat var basicConstraints = cert.Extensions["2.5.29.19"] as X509BasicConstraintsExtension; if (basicConstraints == null || !basicConstraints.CertificateAuthority) { throw new ArgumentException("Ni CA certifikat"); } _trustedRoots.Add(cert); Console.WriteLine($"Dodan zaupanja vreden korenski certifikat: {cert.Subject}"); } public void AddTrustedIntermediate(string certPath) { var cert = new X509Certificate2(certPath); _trustedIntermediates.Add(cert); Console.WriteLine($"Dodan zaupanja vreden vmesni certifikat: {cert.Subject}"); } public X509Chain CreateChain() { var chain = new X509Chain(); chain.ChainPolicy.CustomTrustStore.AddRange(_trustedRoots); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; chain.ChainPolicy.ExtraStore.AddRange(_trustedIntermediates); chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(15); return chain; } public bool ValidateCertificate(X509Certificate2 cert) { using var chain = CreateChain(); return chain.Build(cert); } } ---- ===== Logika ponovnih poskusov pri TLS napakah ===== public class ResilientTlsClient { private readonly HttpClient _client; private readonly int _maxRetries; public ResilientTlsClient(HttpClient client, int maxRetries = 3) { _client = client; _maxRetries = maxRetries; } public async Task GetWithRetry(string url) { Exception? lastException = null; for (int attempt = 1; attempt <= _maxRetries; attempt++) { try { return await _client.GetAsync(url); } catch (HttpRequestException ex) when (IsTlsError(ex)) { lastException = ex; Console.WriteLine($"TLS napaka (poskus {attempt}/{_maxRetries}): {ex.Message}"); if (attempt < _maxRetries) { await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt))); } } } throw new HttpRequestException($"Neuspešno po {_maxRetries} poskusih", lastException); } private bool IsTlsError(HttpRequestException ex) { return ex.InnerException is AuthenticationException || ex.Message.Contains("SSL") || ex.Message.Contains("TLS"); } } ---- ===== Panožne zahteve za odjemalce ===== ^ Panoga ^ Shramba zaupanja ^ Pripenjanje ^ Časovna omejitev ^ | **Finance** | Lastna PKI | Obvezno | 30 sekund | | **Zdravstvo** | gematik TSL | Priporočeno | 60 sekund | | **IoT** | Vgrajeno | Obvezno | 120 sekund | | **Podjetja** | AD/GPO porazdeljeno | Opcijsko | 30 sekund | ---- ===== Povezani scenariji ===== ^ Povezava ^ Scenarij ^ Opis ^ | **Predpogoj** | [[.:server_setup|10.1 TLS strežnik]] | Konfiguracija strežnika | | **Razširitev** | [[.:mtls_deployment|10.3 Uvajanje mTLS]] | Dodajanje odjemalčevega certifikata | | **Povezano** | [[sl:int:pqcrypt:szenarien:validierung:chain_validation|5.2 Validacija verige]] | Preverjanje certifikata | ---- << [[.:server_setup|← 10.1 TLS strežnik]] | [[.:start|↑ Pregled TLS]] | [[.:mtls_deployment|10.3 Uvajanje mTLS →]] >> {{tag>scenarij tls odjemalec httpclient shramba-zaupanja pripenjanje}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//