androidengineers.Book a session

Network Architecture

Network Security: TLS & Pinning

article20 minHard

Transport security is the first line of defense for your app's data in transit. Android gives you several layers: platform TLS defaults, Network Security Config, and certificate pinning.

Android Network Security Config

The network_security_config.xml file declaratively controls your app's network security policy — no code required for most use cases.

<!-- res/xml/network_security_config.xml -->
<network-security-config>
    <!-- Block cleartext traffic everywhere -->
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="system" />  <!-- trust system CAs -->
        </trust-anchors>
    </base-config>

    <!-- Allow cleartext for a specific debug host -->
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="false">10.0.2.2</domain>  <!-- emulator localhost -->
    </domain-config>
</network-security-config>
<!-- AndroidManifest.xml -->
<application
    android:networkSecurityConfig="@xml/network_security_config" ...>

Certificate Pinning

Pinning ensures your app only trusts a specific certificate (or public key), preventing MitM attacks even if a CA is compromised.

Option 1: Network Security Config (declarative)

<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">api.example.com</domain>
        <pin-set expiration="2026-01-01">
            <!-- Primary pin: SHA-256 of the SubjectPublicKeyInfo -->
            <pin digest="SHA-256">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</pin>
            <!-- Backup pin: different cert (rotate before primary expires) -->
            <pin digest="SHA-256">BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=</pin>
        </pin-set>
    </domain-config>
</network-security-config>

Get pin values:

openssl s_client -connect api.example.com:443 | \
  openssl x509 -pubkey -noout | \
  openssl pkey -pubin -outform der | \
  openssl dgst -sha256 -binary | base64

Option 2: OkHttp CertificatePinner (programmatic)

val certificatePinner = CertificatePinner.Builder()
    .add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
    .add("api.example.com", "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=")  // backup
    .build()

val okHttpClient = OkHttpClient.Builder()
    .certificatePinner(certificatePinner)
    .build()

If the pin doesn't match, OkHttp throws SSLPeerUnverifiedException — treat this as a security event and alert your backend.

Risks of Certificate Pinning

Pinning requires careful management:

RiskMitigation
Certificate expires without pin updateAlways include a backup pin; set expiration reminders
App update lag (users on old versions)Use public key pinning (more stable than cert pinning)
Pin mismatch blocks all usersHave a server-side kill switch / config to disable pinning
Testing with Charles/Fiddler breaksMaintain a debug build without pinning; never ship without it

Detecting MitM Proxies (Testing)

# Trust a custom CA for debugging — safe in debug builds only
adb shell settings put global http_proxy 192.168.1.100:8888

In your debug Network Security Config, add the proxy CA:

<debug-overrides>
    <trust-anchors>
        <certificates src="system" />
        <certificates src="user" />  <!-- allows user-installed CAs like Charles -->
    </trust-anchors>
</debug-overrides>

Never include <certificates src="user"/> in release builds — it allows interception.

TLS Version & Cipher Suites

Android 10+ enforces TLS 1.2 minimum by default. Android 12+ makes TLS 1.3 preferred. You can restrict further with a custom SSLSocketFactory in OkHttp, but the Android defaults are already strong.

// Verify TLS version in use
val connection = URL("https://api.example.com").openConnection() as HttpsURLConnection
println("Protocol: ${connection.cipher}")

Key Takeaways

ConceptRule
Network Security ConfigUse to block cleartext and configure trust anchors declaratively
Certificate pinningAlways include ≥ 2 pins (primary + backup); use public key pinning
Pin rotationUpdate app before certificate expires; never pin to leaf cert alone
Debug buildsAllow user CAs in debug only; never in release
SSLPeerUnverifiedExceptionLog as security event, not a normal error

YOUR LEARNING JOURNEY

0 of 177 available lessons completed

Progress saved in this browser. No account needed.
Network Security: TLS & Pinning | Android System Design | Android Engineers