Skip to content
advanced Phase 8 · Networking

Network Security

Configure network security: certificate pinning, cleartext traffic, and custom trust managers.

40m
0 problems
Topic Progress 0%

Android Network Security Configuration

What Is network_security_config.xml?

Android 7.0 (API 24) introduced network_security_config.xml, a declarative way to configure TLS settings, cleartext traffic, and certificate trusts without writing code.

<!-- res/xml/network_security_config.xml -->
<network-security-config>
    <!-- Block cleartext (HTTP) traffic in production -->
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>

    <!-- Allow cleartext for local development -->
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">10.0.2.2</domain>
        <domain includeSubdomains="true">localhost</domain>
    </domain-config>

    <!-- Certificate pinning for your API -->
    <domain-config>
        <domain includeSubdomains="true">api.yourapp.com</domain>
        <pin-set expiration="2025-12-31">
            <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
            <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
        </pin-set>
    </domain-config>
</network-security-config>

Reference it in your manifest:

<application
    android:networkSecurityConfig="@xml/network_security_config"
    ... >

Why Block Cleartext?

Cleartext HTTP traffic is vulnerable to eavesdropping and tampering. On Android 9+, cleartext is blocked by default. If your app still needs HTTP (for local dev or third-party services), you must explicitly permit it per domain.

// Checking network connectivity and security at runtime
fun isNetworkSecure(context: Context): Boolean {
    val connectivityManager = context.getSystemService<ConnectivityManager>()
    val network = connectivityManager?.activeNetwork ?: return false
    val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
    return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}

Certificate Pinning and Trust

How TLS Certificate Validation Works

When your app connects to api.yourapp.com, the server presents a certificate. Your device validates it by checking:

  1. Is the certificate signed by a trusted Certificate Authority (CA)?
  2. Is the certificate for the correct domain?
  3. Has the certificate expired?
  4. Has the certificate been revoked?

Certificate pinning adds step 5: Does the certificate match a known fingerprint?

Why Pin Certificates?

A compromised CA can issue fraudulent certificates. Without pinning, an attacker with a rogue certificate can intercept all traffic via a MITM proxy. Pinning limits which certificates your app trusts, even if a CA is compromised.

Pinning with OkHttp

fun createPinnedClient(): OkHttpClient {
    val certificatePinner = CertificatePinner.Builder()
        .add(
            "api.yourapp.com",
            "sha256/7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y="
        )
        .add(
            "api.yourapp.com",
            "sha256/fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE="
        )
        .build()

    return OkHttpClient.Builder()
        .certificatePinner(certificatePinner)
        .build()
}

Always provide at least two pins: your current certificate and a backup. If you lose access to your private key, the backup pin keeps your app working.

Custom Trust Managers

For enterprise environments where you need to trust a private CA:

fun createCustomTrustClient(context: Context): OkHttpClient {
    val cf = CertificateFactory.getInstance("X.509")
    val ca = context.resources.openRawResource(R.raw.private_ca).use {
        cf.generateCertificate(it)
    }

    val keyStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
        load(null, null)
        setCertificateEntry("ca", ca)
    }

    val trustManagerFactory = TrustManagerFactory.getInstance(
        TrustManagerFactory.getDefaultAlgorithm()
    ).apply {
        init(keyStore)
    }

    val sslContext = SSLContext.getInstance("TLS").apply {
        init(null, trustManagerFactory.trustManagers, null)
    }

    return OkHttpClient.Builder()
        .sslSocketFactory(sslContext.socketFactory, trustManagerFactory.trustManagers[0] as X509TrustManager)
        .build()
}

Warning: Custom trust managers bypass the system trust store. Only use them for legitimate private CAs, never to disable certificate validation.

Production Security Checklist

Network Security Checklist

  1. Disable cleartext in production via network_security_config.xml
  2. Pin certificates for your primary API domain with at least two pins
  3. Use HTTPS everywhere - never send tokens or user data over HTTP
  4. Validate hostnames - ensure OkHttp does not follow redirects to different domains
  5. Rotate pins before expiration using the expiration attribute in pin-set

Hostname Verification

OkHttp verifies hostnames by default. Disable this only for testing:

// NEVER do this in production
val unsafeClient = OkHttpClient.Builder()
    .hostnameVerifier { _, _ -> true } // Disables hostname verification!
    .build()

Token Security on Android

Store tokens in EncryptedSharedPreferences, never in plain text:

val masterKey = MasterKey.Builder(context)
    .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
    .build()

val securePrefs = EncryptedSharedPreferences.create(
    context,
    "secure_prefs",
    masterKey,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

// Store token
securePrefs.edit().putString("auth_token", token).apply()

// Read token
val token = securePrefs.getString("auth_token", null)

Network Safety with Certificate Transparency

Certificate Transparency (CT) logs all issued certificates publicly. Android 15+ enforces CT for new apps. You can add CT checks to OkHttp with the certificatetransparency library:

val client = OkHttpClient.Builder()
    .certificatePinner(
        CertificatePinner.Builder()
            .add("api.yourapp.com", "sha256/...")
            .build()
    )
    .build()

Common Vulnerabilities

Vulnerability Mitigation
Cleartext HTTP Block via network security config
Expired certificates Rotate pins before expiration
Rogue CA certificates Certificate pinning
Token leakage in logs Disable BODY logging in production
Insecure storage EncryptedSharedPreferences
Open redirect Disable followSslRedirects or validate domains

Quiz

1. What is the purpose of certificate pinning?

Question 1 options

2. Why should you provide at least two certificate pins?

Question 2 options

3. What does cleartextTrafficPermitted=false do in network_security_config.xml?

Question 3 options

4. Why should tokens never be stored in plain SharedPreferences?

Question 4 options

Flashcards

Question

What is a Man-in-the-Middle (MITM) attack?

Answer

An attacker intercepts communication between the app and server by presenting a fraudulent certificate. Certificate pinning prevents this by only trusting certificates with known fingerprints.

Question

What is the difference between network_security_config.xml and OkHttp certificate pinning?

Answer

network_security_config.xml is a system-level config that applies to all HTTP clients on the device. OkHttp certificate pinning applies only to requests made through that specific OkHttp client instance.

Question

What does EncryptedSharedPreferences use to protect data?

Answer

It uses the Android Keystore system with AES-256 encryption. The encryption keys are stored in hardware-backed secure storage on supported devices.

Question

Why is hostname verification important?

Answer

It ensures the server certificate is valid for the domain you are connecting to. Without it, an attacker could present a valid certificate for a different domain and intercept your traffic.

Revision Notes

Key Takeaways

  • 1. Block cleartext traffic in production via network_security_config.xml
  • 2. Pin at least two certificate hashes with a rotation strategy
  • 3. Store sensitive data in EncryptedSharedPreferences, never plain storage
  • 4. Never disable hostname verification or certificate validation in production

Interview Tips

  • Explain how certificate pinning prevents MITM attacks
  • Discuss the difference between system-level and app-level TLS configuration
  • Describe how you would rotate pinned certificates without breaking existing app versions
  • Know why Android blocks cleartext by default and when you might need exceptions

Cheat Sheet

Network Security Cheat Sheet

network_security_config.xml:

  • cleartextTrafficPermitted=false blocks HTTP
  • pin-set with SHA-256 pins for your domain
  • domain-config for dev/local exceptions
  • Reference in AndroidManifest.xml

Certificate Pinning:

  • Always provide 2+ pins (current + backup)
  • Set expiration date for pin rotation
  • Use OkHttp CertificatePinner.Builder()
  • Pin the SPKI hash, not the full certificate

Token Security:

  • Store in EncryptedSharedPreferences
  • Never log tokens or secrets
  • Use Android Keystore for key management
  • Clear tokens on logout

Checklist:

  • Block cleartext in production
  • Pin certificates for primary API
  • Validate hostnames
  • Never disable SSL verification