masvs_category | platform |
---|---|
MASVS-NETWORK |
android |
Almost every Android app acts as a client to one or more remote services. As this network communication usually takes place over untrusted networks such as public Wi-Fi, classical network based-attacks become a potential issue.
Most modern mobile apps use variants of HTTP-based web services, as these protocols are well-documented and supported.
Starting on Android 7.0 (API level 24), Android apps can customize their network security settings using the so-called Network Security Configuration feature which offers the following key capabilities:
- Cleartext traffic: Protect apps from accidental usage of cleartext traffic (or enables it).
- Custom trust anchors: Customize which Certificate Authorities (CAs) are trusted for an app's secure connections. For example, trusting particular self-signed certificates or restricting the set of public CAs that the app trusts.
- Certificate pinning: Restrict an app's secure connection to particular certificates.
- Debug-only overrides: Safely debug secure connections in an app without added risk to the installed base.
If an app defines a custom Network Security Configuration, you can obtain its location by searching for android:networkSecurityConfig
in the AndroidManifest.xml file.
<application android:networkSecurityConfig="@xml/network_security_config"
In this case the file is located at @xml
(equivalent to /res/xml) and has the name "network_security_config" (which might vary). You should be able to find it as "res/xml/network_security_config.xml". If a configuration exists, the following event should be visible in the system logs (@MASTG-TECH-0009):
D/NetworkSecurityConfig: Using Network Security Config from resource network_security_config
The Network Security Configuration is XML-based and can be used to configure app-wide and domain-specific settings:
base-config
applies to all connections that the app attempts to make.domain-config
overridesbase-config
for specific domains (it can contain multipledomain
entries).
For example, the following configuration uses the base-config
to prevent cleartext traffic for all domains. But it overrides that rule using a domain-config
, explicitly allowing cleartext traffic for localhost
.
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="false" />
<domain-config cleartextTrafficPermitted="true">
<domain>localhost</domain>
</domain-config>
</network-security-config>
Learn more:
- "A Security Analyst’s Guide to Network Security Configuration in Android P"
- Android Developers - Network Security Configuration
- Android Codelab - Network Security Configuration
The default configuration for apps targeting Android 9 (API level 28) and higher is as follows:
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
The default configuration for apps targeting Android 7.0 (API level 24) to Android 8.1 (API level 27) is as follows:
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
The default configuration for apps targeting Android 6.0 (API level 23) and lower is as follows:
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
Certificate pinning can be employed in Android apps to safeguard against Machine-in-the-Middle (MITM) attacks by ensuring that the app communicates exclusively with remote endpoints possessing specific identities.
While effective when implemented correctly, insecure implementations potentially enable attackers to read and modify all communication. For more general details on pinning, refer to @MASWE-0047.
Several approaches to certificate pinning exist, depending on the app's API level and the libraries used. Below, we highlight the most common methods. For a deeper dive into the specific implementations, see "Deep Dive into Certificate Pinning on Android".
Important Considerations:
Certificate pinning is a hardening practice, but it is not foolproof. There are multiple ways an attacker can bypass it, such as:
- Modifying the certificate validation logic in the app's
TrustManager
. - Replacing pinned certificates stored in resource directories (
res/raw/
,assets/
). - Altering or removing pins in the Network Security Configuration.
Any such modification invalidates the APK signature, requiring the attacker to repackage and re-sign the APK. To mitigate these risks, additional protections such as integrity checks, runtime verification, and obfuscation may be required. For more information on the specific techniques, see @MASTG-TECH-0012.
The Network Security Configuration (NSC) is the preferred and recommended way to implement certificate pinning in Android, as it provides a declarative, maintainable, and secure approach without requiring code changes. It applies to all network traffic managed by the Android framework within the app, including HttpsURLConnection
-based connections and WebView
requests (unless a custom TrustManager
is used). For communication from native code, NSC does not apply, and other mechanisms need to be considered.
When attempting to establish a connection to a remote endpoint, the system will:
- Get and validate the incoming certificate.
- Extract the public key.
- Calculate a digest over the extracted public key.
- Compare the digest with the set of local pins.
If at least one of the pinned digests matches, the certificate chain will be considered valid and the connection will proceed.
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<!-- Use certificate pinning for OWASP website access including sub domains -->
<domain includeSubdomains="true">owasp.org</domain>
<pin-set expiration="2028-12-31">
<!-- Hash of the public key (SubjectPublicKeyInfo of the X.509 certificate) of
the Intermediate CA of the OWASP website server certificate -->
<pin digest="SHA-256">YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=</pin>
<!-- Hash of the public key (SubjectPublicKeyInfo of the X.509 certificate) of
the Root CA of the OWASP website server certificate -->
<pin digest="SHA-256">Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=</pin>
</pin-set>
</domain-config>
</network-security-config>
Important Considerations:
- Backup Pins: Always include a backup pin to maintain connectivity if the primary certificate changes unexpectedly.
- Expiration Dates: Set an appropriate expiration date and ensure timely updates to prevent the app from bypassing pinning after the date has passed.
- Scope of Application: Be aware that this configuration applies only to connections made using
HttpsURLConnection
or libraries that rely on it. Other networking libraries or frameworks may require separate pinning implementations.
Before Network Security Configuration became available, the recommended way to implement certificate pinning was to create a custom TrustManager
(using javax.net.ssl
APIs) and override the default certificate validation. You can still use this approach on modern Android versions for flexibility or when you need more direct control.
This approach involves:
- Loading the server's certificate(s) into a
KeyStore
. - Creating a custom
TrustManager
that only trusts the certificate(s) in theKeyStore
. - Initializing an
SSLContext
with the customTrustManager
. - Applying the custom
SSLContext
as the socket factory for the network connections (e.g.,HttpsURLConnection
).
Important Note: This is a low-level approach and is prone to errors if not done carefully. Some key considerations include:
SSLSocket
does not automatically verify hostnames, so you must handle this manually using aHostnameVerifier
with a safe implementation (this includes explicitly checking the return value ofHostnameVerifier.verify()
). More information can be found in the Android documentation.- Do not include a "trust-all"
TrustManager
that silently accepts all certificates. This opens the door for attackers to intercept and modify user data with minimal effort.
Several third-party libraries offer built-in support for certificate pinning, simplifying the implementation process in some cases. These libraries typically utilize the custom TrustManager
method, providing higher-level abstractions and additional features. Notable examples include:
For example, OkHttp's offers pinning in its CertificatePinner
. Under the hood, it uses a custom TrustManager
to enforce pinning rules.
For in-app WebView
traffic on Android, the easiest approach is to rely on the Network Security Configuration. Since Android automatically applies NSC rules to WebView traffic within the same application, any pinning rules you set up in network_security_config.xml
will also apply to resources loaded in that WebView.
If you need additional customization beyond what NSC offers, you could implement pinning by intercepting requests at the WebView level (e.g., using shouldInterceptRequest
and a custom TrustManager
), but in most cases the built-in support is sufficient and simpler.
It's also possible to implement pinning in native code (C/C++/Rust). By embedding or dynamically verifying certificates within compiled native libraries (.so
files), you can increase the difficulty of bypassing or modifying the pinning checks via typical APK reverse engineering.
That said, this approach requires significant security expertise and a careful design to manage certificates or public key hashes in native space. Maintenance and debugging also typically become more complex.
Cross-platform frameworks like Flutter, React Native, Cordova, and Xamarin often require special considerations for certificate pinning, as they may not use the same network stack as native apps. For example, Flutter relies on its own Dart HttpClient
(with BoringSSL) instead of the platform's networking stack, while Cordova makes network requests through JavaScript in a WebView. As a result, pinning behavior varies—some frameworks provide built-in configuration options, others rely on third-party plugins, and some offer no direct support but allow manual implementation via APIs. Understanding how a framework handles networking is crucial for ensuring proper pinning enforcement.
Android relies on a security provider to provide SSL/TLS-based connections. The problem with this kind of security provider (one example is OpenSSL), which comes with the device, is that it often has bugs and/or vulnerabilities.
To avoid known vulnerabilities, developers need to make sure that the application will install a proper security provider. Since July 11, 2016, Google has been rejecting Play Store application submissions (both new applications and updates) that use vulnerable versions of OpenSSL.