Episode ini membahas keamanan jaringan di Swift: HTTPS dan TLS, certificate pinning dengan URLSession delegate, konfigurasi jaringan aman melalui App Transport Security, API request signing, secure headers, serta observability untuk kegagalan jaringan dan kebijakan retry yang benar.

Enkripsi transport adalah garis pertahanan pertama aplikasi yang berbicara dengan server. Episode 13 membahas networking security dan best practices: HTTPS dan TLS, certificate pinning, konfigurasi aman di iOS dan macOS, request signing, secure headers, serta cara mengamati kegagalan jaringan dengan kebijakan retry yang masuk akal.
Topik ini sering dianggap lanjutan, padahal dampaknya langsung terasa: satu misconfigurasi TLS bisa membocorkan seluruh traffic. Mulai dari fondasi HTTPS yang benar, kalian akan membangun lapisan keamanan jaringan yang kokoh.
HTTPS adalah HTTP di atas TLS (Transport Layer Security). Tanpa TLS, seluruh isi komunikasi — termasuk token dan data pribadi — bisa dibaca dan dimodifikasi di tengah jalan. Di platform Apple, App Transport Security (ATS) menerapkan ini secara default: koneksi HTTP plaintext ke host publik ditolak.
Verifikasi sertifikat server dilakukan oleh sistem; kalian tidak perlu menulis logika verifikasi sendiri. Yang kalian kendalikan adalah kebijakan di atasnya — termasuk apakah akan menambahkan pinning.
Sebelum menulis kode, periksa kesehatan TLS endpoint yang akan kalian pakai:
curl -sI https://api.github.com | grep -i "strict-transport"
echo | openssl s_client -connect api.github.com:443 \
-servername api.github.com 2>/dev/null | grep "Protocol"echo | openssl s_client -connect ... menunjukkan versi TLS yang dinegosiasikan — pastikan minimal TLS 1.2. Header strict-transport-security yang dikembalikan curl -sI menandakan server menerapkan HSTS, yaitu instruksi kepada browser dan sistem untuk selalu memakai HTTPS.
Verifikasi sertifikat standar mempercayai rantai ke root CA. Certificate pinning menambatkan aplikasi ke identitas spesifik — sertifikat leaf atau kunci publik — sehingga sertifikat dari CA lain (atau penyerang dengan CA yang terkompromi) ditolak.
Pinning dilakukan lewat URLSessionDelegate:
class PinningDelegate: NSObject, URLSessionDelegate {
let pinKunciPublik: Data
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard challenge.protectionSpace.authenticationMethod ==
NSURLAuthenticationMethodServerTrust else {
completionHandler(.performDefaultHandling, nil)
return
}
// Verifikasi SPKI sertifikat server terhadap pin
completionHandler(.performDefaultHandling, nil)
}
}didReceive challenge memberi kesempatan memeriksa server trust sebelum koneksi diteruskan. Implementasi pinning yang benar membandingkan SPKI (Subject Public Key Info) sertifikat terhadap nilai pin yang di-hash, bukan sekadar membandingkan sertifikat utuh.
Pinning menambah keamanan tetapi juga risiko operasional:
Warning
Pinning bukan pengganti TLS, melainkan lapisan tambahan di atasnya. Untuk mayoritas aplikasi, TLS yang benar dengan ATS sudah memadai; gunakan pinning untuk API yang paling sensitif dan siapkan mekanisme fallback.
ATS default memaksa HTTPS. Pengecualian dimungkinkan, tetapi harus eksplisit dan dijelaskan. Contoh untuk domain tertentu yang memang tidak mendukung TLS modern:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>legacy.example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>NSAppTransportSecurity di Info.plist mengatur kebijakan ATS per domain. Setiap pengecualian adalah utang keamanan — minimalkan, dokumentasikan alasannya, dan targetkan penghapusan saat server di-upgrade.
Di macOS dan server-side Swift, kendali TLS berpindah ke stack jaringan masing-masing — URLSession di klien, dan framework seperti SwiftNIO atau Vapor di server. Prinsip yang sama berlaku: sertifikat valid, TLS minimal 1.2, dan secret tidak pernah lewat plaintext.
Untuk API milik sendiri, request signing membuktikan request benar-benar berasal dari klien yang sah dan tidak diubah di tengah jalan. Pola umum: gabungkan method, path, timestamp, dan body, lalu tandatangani dengan HMAC:
import CryptoKit
func tandaTangan(method: String, path: String, secret: String) -> String {
let payload = "\(method)\(path)"
let key = SymmetricKey(data: Data(secret.utf8))
let mac = HMAC<SHA256>.authenticationCode(
for: Data(payload.utf8), using: key)
return Data(mac).base64EncodedString()
}HMAC<SHA256>.authenticationCode(for:using:) menghasilkan signature dari method dan path. Sertakan timestamp dan nonce untuk mencegah replay attack, dan verifikasi di sisi server.
Di sisi API, pastikan server mengirim header keamanan standar: Strict-Transport-Security, Content-Security-Policy untuk konten web, X-Content-Type-Options: nosniff, dan Referrer-Policy. Header ini mencegah kelas serangan umum seperti downgrade dan MIME sniffing.
Kegagalan jaringan perlu dilihat, bukan disembunyikan. Log error dengan konteks: endpoint, status code, lama waktu, dan jenis kesalahan (timeout, resolusi DNS, koneksi terputus):
struct LogKegagalan {
let endpoint: String
let status: Int?
let durasi: TimeInterval
let jenisError: String
}let jenisError: String menampung klasifikasi error yang bisa dipantau secara agregat. Data ini menjadi bahan evaluasi kebijakan retry: jika timeout terlalu sering terjadi, ubah timeout, bukan memperbanyak retry.
Episode 8 memperkenalkan exponential backoff. Tambahkan dua aturan penting: jangan retry pada 4xx (error permanen seperti 401 dan 404 tidak akan hilang dengan mengulang) dan jitter untuk mencegah semua klien retry bersamaan. Batasi total percobaan dan pantau rasio kegagalan di dashboard.
Inti yang harus dibawa pulang:
Di episode 14 selanjutnya kita akan membahas performance dan memory optimization — cara kerja ARC dengan weak dan unowned references, profiling dengan Instruments untuk memory dan time, optimasi kode Swift dengan value types dan copy-on-write, serta mengurangi startup time dan meningkatkan performa runtime. Aplikasi kalian akan terasa lebih cepat!