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
}
}
}