Implementing Transport Layer Security

Implementing Transport Layer Security

TLS/SSL forms the foundation of secure network communication, but proper implementation requires attention to detail and platform-specific considerations.

iOS Network Security Implementation:

// iOS - Comprehensive network security configuration
import Foundation

class SecureNetworkManager: NSObject {
    
    private lazy var session: URLSession = {
        let configuration = URLSessionConfiguration.default
        
        // Configure TLS settings
        configuration.tlsMinimumSupportedProtocolVersion = .TLSv12
        configuration.tlsMaximumSupportedProtocolVersion = .TLSv13
        
        // Set timeout values
        configuration.timeoutIntervalForRequest = 30
        configuration.timeoutIntervalForResource = 60
        
        // Disable caching for sensitive data
        configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
        configuration.urlCache = nil
        
        return URLSession(
            configuration: configuration,
            delegate: self,
            delegateQueue: nil
        )
    }()
    
    // Perform secure request with retry logic
    func performSecureRequest(
        to url: URL,
        method: String = "GET",
        headers: [String: String] = [:],
        body: Data? = nil,
        completion: @escaping (Result<Data, Error>) -> Void
    ) {
        var request = URLRequest(url: url)
        request.httpMethod = method
        request.httpBody = body
        
        // Add security headers
        request.setValue("no-cache, no-store, must-revalidate", forHTTPHeaderField: "Cache-Control")
        request.setValue("no-cache", forHTTPHeaderField: "Pragma")
        request.setValue("0", forHTTPHeaderField: "Expires")
        
        // Add custom headers
        headers.forEach { key, value in
            request.setValue(value, forHTTPHeaderField: key)
        }
        
        performRequest(request, retryCount: 3, completion: completion)
    }
    
    private func performRequest(
        _ request: URLRequest,
        retryCount: Int,
        completion: @escaping (Result<Data, Error>) -> Void
    ) {
        let task = session.dataTask(with: request) { [weak self] data, response, error in
            if let error = error {
                if retryCount > 0 && self?.isRetryableError(error) == true {
                    // Retry with exponential backoff
                    let delay = pow(2.0, Double(3 - retryCount))
                    DispatchQueue.global().asyncAfter(deadline: .now() + delay) {
                        self?.performRequest(request, retryCount: retryCount - 1, completion: completion)
                    }
                } else {
                    completion(.failure(error))
                }
                return
            }
            
            guard let httpResponse = response as? HTTPURLResponse else {
                completion(.failure(NetworkError.invalidResponse))
                return
            }
            
            // Validate response
            guard (200...299).contains(httpResponse.statusCode) else {
                completion(.failure(NetworkError.httpError(statusCode: httpResponse.statusCode)))
                return
            }
            
            guard let data = data else {
                completion(.failure(NetworkError.noData))
                return
            }
            
            completion(.success(data))
        }
        
        task.resume()
    }
}

// MARK: - URLSessionDelegate
extension SecureNetworkManager: URLSessionDelegate {
    
    func urlSession(
        _ session: URLSession,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
    ) {
        guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
              let serverTrust = challenge.protectionSpace.serverTrust else {
            completionHandler(.cancelAuthenticationChallenge, nil)
            return
        }
        
        // Implement certificate pinning
        if let pinnedCertificates = loadPinnedCertificates(for: challenge.protectionSpace.host) {
            if validateCertificateChain(serverTrust, against: pinnedCertificates) {
                let credential = URLCredential(trust: serverTrust)
                completionHandler(.useCredential, credential)
            } else {
                completionHandler(.cancelAuthenticationChallenge, nil)
            }
        } else {
            // Fall back to default validation for non-pinned hosts
            let credential = URLCredential(trust: serverTrust)
            completionHandler(.useCredential, credential)
        }
    }
    
    private func validateCertificateChain(
        _ serverTrust: SecTrust,
        against pinnedCertificates: [SecCertificate]
    ) -> Bool {
        // Set pinned certificates as anchor certificates
        SecTrustSetAnchorCertificates(serverTrust, pinnedCertificates as CFArray)
        SecTrustSetAnchorCertificatesOnly(serverTrust, true)
        
        // Evaluate trust
        var error: CFError?
        let isValid = SecTrustEvaluateWithError(serverTrust, &error)
        
        return isValid
    }
}

Android Network Security Configuration:

// Android - Comprehensive network security implementation
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.*

class SecureApiClient(private val context: Context) {
    
    companion object {
        private const val BASE_URL = "https://api.example.com/"
        private const val CONNECT_TIMEOUT = 30L
        private const val READ_TIMEOUT = 30L
        private const val WRITE_TIMEOUT = 30L
    }
    
    private val okHttpClient: OkHttpClient by lazy {
        createSecureOkHttpClient()
    }
    
    val retrofit: Retrofit by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
    
    private fun createSecureOkHttpClient(): OkHttpClient {
        val builder = OkHttpClient.Builder()
        
        // Configure timeouts
        builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
        
        // Add certificate pinning
        val certificatePinner = CertificatePinner.Builder()
            .add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
            .add("api.example.com", "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=")
            .build()
        
        builder.certificatePinner(certificatePinner)
        
        // Add custom interceptors
        builder.addInterceptor(SecurityHeadersInterceptor())
        builder.addInterceptor(AuthenticationInterceptor(context))
        
        // Add logging interceptor for debug builds only
        if (BuildConfig.DEBUG) {
            val loggingInterceptor = HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.HEADERS
            }
            builder.addInterceptor(loggingInterceptor)
        }
        
        // Configure custom SSL socket factory for additional security
        try {
            val trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm()
            )
            trustManagerFactory.init(null as KeyStore?)
            
            val trustManagers = trustManagerFactory.trustManagers
            if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
                throw IllegalStateException("Unexpected default trust managers")
            }
            
            val trustManager = trustManagers[0] as X509TrustManager
            
            val sslContext = SSLContext.getInstance("TLS")
            sslContext.init(null, arrayOf<TrustManager>(trustManager), null)
            
            val sslSocketFactory = sslContext.socketFactory
            
            builder.sslSocketFactory(sslSocketFactory, trustManager)
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
        
        return builder.build()
    }
    
    // Security headers interceptor
    class SecurityHeadersInterceptor : Interceptor {
        override fun intercept(chain: Interceptor.Chain): Response {
            val originalRequest = chain.request()
            
            val modifiedRequest = originalRequest.newBuilder()
                .header("X-Requested-With", "XMLHttpRequest")
                .header("Cache-Control", "no-cache, no-store, must-revalidate")
                .header("Pragma", "no-cache")
                .header("Expires", "0")
                .build()
            
            return chain.proceed(modifiedRequest)
        }
    }
    
    // Authentication interceptor
    class AuthenticationInterceptor(private val context: Context) : Interceptor {
        override fun intercept(chain: Interceptor.Chain): Response {
            val originalRequest = chain.request()
            
            // Get auth token from secure storage
            val authToken = SecurePreferencesManager(context).getAuthToken()
            
            val authenticatedRequest = if (authToken != null) {
                originalRequest.newBuilder()
                    .header("Authorization", "Bearer $authToken")
                    .build()
            } else {
                originalRequest
            }
            
            val response = chain.proceed(authenticatedRequest)
            
            // Handle 401 Unauthorized
            if (response.code == 401) {
                // Refresh token logic
                val newToken = refreshAuthToken()
                if (newToken != null) {
                    // Retry with new token
                    val newRequest = originalRequest.newBuilder()
                        .header("Authorization", "Bearer $newToken")
                        .build()
                    
                    response.close()
                    return chain.proceed(newRequest)
                }
            }
            
            return response
        }
        
        private fun refreshAuthToken(): String? {
            // Implement token refresh logic
            return null
        }
    }
}