π Hi and welcome to the third post in this series where we deep-dive into Android Security. This series focuses on theΒ Top 10 MobileΒ security threats as determined byΒ The Open Web Application Security Project (OWASP) Foundation, the leading application security community in our field.
Before checking this post, please consider checking out the previous one βInsecure Data Storageβ which is available on my site, and on Medium.
β οΈ Please note that this series is for educational purposesΒ only. Remember to only test on apps where you have permission to do so and most of all,Β donβt be evil.
Finally, if you enjoy this series or have any feedback,Β please drop me a message. Thanks!
Introduction
In this helping of my series on Android Security, we shall take a look into the #3 threat to mobile application security as determined by OWASP, βInsecure Communicationβ.
When we talk about communication in the context of mobile security, we are actually referring to technologies that can transmit and/or receive data. This may include the deviceβs internet connection (via WiFi or otherwise), connection to the mobile network, Bluetooth, NFC, and so on and so forth. This unfortunately gives us a pretty broad surface area to cover π However, letβs address the big one today, as perhaps we will revisit this in the future!
The Internet
Unless an app has some very bespoke communication functionality or none at all, itβs more than likely it communicates via the internet with one or more services ΒΉ. This could take the form of requests to an API, visiting a webpage in an in-app browser and pretty muchΒ everythingΒ in-between. The list of possibilities is near-endless, which means there is plenty of attack surface for malicious actors to prey upon.
For the sake of brevity I wonβt cover an βendless listβ, let us instead cover some of the blindingly obvious points and answer the critical question of βHowΒ shouldΒ we be making calls over the network?β.
Top Tip #1: Always make calls using HTTPS
At the time of writing, we are already approaching the halfway point of the year 2022. However, believe it or not, we still live in a world where occasionally mobile apps do not transmit data via HTTPS.
βWhat is HTTPS and why does it even matter?β
HTTPS is the security-enriched use of the Hypertext Transfer Protocol (HTTP), the fundamental protocol (i.e. a pre-defined set of rules) used when communicating on the internet.
βOk, so the βSβ stands for secure, but how does HTTP actually become HTTPS?β
HTTPS utilises Transport Layer Security (TLS)Β², another protocol, to communicate securely using cryptography to encrypt data in transit between client and server. This cryptography is achieved, in part, through the use of βdigital certificatesβ (more on those shortly). Therefore, whenever an application sends data via HTTPS it is encrypted and avoids threats such asΒ man-in-the-middleΒ (MITM) attacks where an attacker can intercept HTTP calls, spoof them and let a victim believe they are talking to the legitimate server. It also makes eavesdropping via a compromised network extremely difficult, again thanks to the built-in encryption provided.
From an Android standpoint, if your app targets Android 9 (API level 28) and above, sending data via HTTP (i.e. cleartext) is disabledΒ by default. However, it is possible to disable this for all network calls through the use of theΒ network security config fileΒ or through a manifest fieldΒ android:usesCleartextTraffic
Β³. In generalΒ you should never do thisΒ and instead consider a cleartext ‘allow list’ within your network security file as seen below:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <!-- DO NOT DO THIS TO ALLOW CLEARTEXT --> <base-config cleartextTrafficPermitted="true"> ... </base-config> <!-- DO THIS (BUT ONLY AS A LAST RESORT) --> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">example.com</domain> </domain-config> </network-security-config>
Again, wherever possible,Β avoid doing thisΒ and instead migrate all URLs to use HTTPS. Your users (and conscience) will thank you β¨
Top Tip #2: Donβt blindly trust user certificates
As previously mentioned, one key aspect of securely communicating over the internet is the use of digital certificates β΄.
In order to verify the server isΒ actuallyΒ who they say they are, some form of certificate is required to prove the identity. However, a certificateΒ aloneΒ is not sufficient, as there would be nothing to stop an attacker from creating a fraudulent one and passing it off as legitimate. To combat this, we use a shared βtrusted third-partyβ known as a βcertificate authorityβ (CA) whose signature on a certificate proves a certificate is authentic when the CA is trusted by both the client and server β΅. Your Android device comes pre-loaded with a common list of CAβs that are βtrustedβ, which means you can make secure calls to the internet immediately without (usually) any issues.
However, Android also allows users to supply their own βtrustedβ certificates. The most common use case for user certificates comes through their use with proxy software such as Charles, Fiddler or Wireshark, allowing the capturing of data sent by a device for debugging purposes. They will often provide a certificate for a user to add to their device while proxying through the software, allowing the decryption of secure HTTPS calls and the contents to be freely viewed/modified. For debugging purposes, this is often invaluable and extremely useful,Β but allowingΒ anyΒ user certificate on a production app is a huge security lapse.
You might well be vulnerable if your network security config files contain something similar to the example below. In fact, if your app doesΒ notΒ target Android 7.0 (API level 24) or above it will act like thisΒ by defaultΒ βΆ. This example would allow user certificates to be available on all configurations of the application, including any production/app store builds.
<!-- DO NOT DO THIS --> <network-security-config> <base-config> <trust-anchors> <certificates src="user" /> </trust-anchors> </base-config> </network-security-config>
The recommended approach is to allow user certificates toΒ only be used by your application during debugging. i.e. non-production and non-public facing builds. Thankfully, this is quite straightforward to implement through the use ofΒ debug-overrides
.
<network-security-config> <debug-overrides> <trust-anchors> <certificates src="user" /> </trust-anchors> </debug-overrides> </network-security-config>
Nice. π₯³
Another noteworthy point here. Should your server use aΒ self-signed certificateΒ and not one provided by default CAs, you can also provide the raw PEM or DER certificate file(s) within your app to allow them to be used when networking. By adding one or more of these files toΒ res/raw/trusted_roots
, it becomes possible to import them as a certificate source usingΒ @raw/trusted_roots
Β at the top or domain-specific level.Β The docsΒ are especially helpful in this slightly more niche case, so please give them a read!
Top Tip #3: Certificate pinning & transparency
On the subject of certificates, to further bolster your security you may wish to or have considered certificate βpinningβ. For those who arenβt aware, certificate pinning is the act of checking the chain of certificates for a request against an βexpected certificate hashβ to check it is present. In reality, this is usually the hash of one (or more) of your certificateβs public key and is hard-coded into your application as part of your network layer or again, as part of your network security config XML file.
This is aΒ veryΒ common approach utilised by apps to ensure they are only communicating with the expected server. Nevertheless, this approach has a number of issues, including requiring app releases for certificate rotations and ensuring you make the best choice when it comes to choosing certificates to pin in the chain.
However, there is another slightly lesser-known but arguably much better option on the table π
Certificate TransparencyΒ (CT) is a growing alternative approach and addresses some of the pain points that come with working with certificate pinning. CT is achieved by CAs publicly logging when they have issued a new certificate to a log server. Critically, these log servers are βappend onlyβ, meaning they can only addΒ newΒ data to them. When a new certificate from a CA is issued, the log server issues a signed certificate timestamp (SCT) which can be verified by a client. As there is no longer a reliance on public keys of certificates, the need to release an app when certificates rotate is eliminated and the certificateβs authenticity can be guaranteed.
Matt Dolanβs talkΒ βMove over certificate pinning. Certificate Transparency is here!βΒ gives an excellent insight into how to implement this in your apps, as well as a great overview of both pinning and CT.
Top Tip #4: Donβt log your calls
Youβd be amazed how many times I have downloaded an app to my device, used it for a while, opened logcat and to my horror been greeted by the networking calls I just made staring me in the face. I really wish I was joking. Login credentials, full headers, the works. Iβve seen pretty much everything. Worst of all, I saw itΒ just this monthβ·.
Many of us will use OkHttp within your appβs networking layer and thus potentially also be using theΒ HttpLoggingInterceptor
Β to print your networking calls to logcat. There is absolutely nothing wrong with this, so long as this codeΒ does notΒ make it to the production/public-facing version of your app.
You should certainly consider disablingΒ allΒ logging in your production apps by using R8 to strip theΒ Log
Β class of its functionality. This can be achieved by adding the following rule to your obfuscation file:
-assumenosideeffects class android.util.Log { public static boolean isLoggable(java.lang.String, int); public static int v(...); public static int i(...); public static int w(...); public static int d(...); public static int e(...); }
Job Offers
assumenosideeffects
Β strips any calls to the provided methods from within your app as it assumes the return values aren’t used. This will ensure no logs are output by your app.
However, this extreme approach may not work for everyone. Alternatives include using custom logger implementations (through libraries such asΒ Timber) to discard logs when the app is built using a certain flavour, or just do not useΒ Log
Β at all π
The choice is very much up to you and your situation!
Top Tip #5: If in doubt, use your head!
I do apologise if this sounds condescending, and admittedly this is not just limited to this particular area of security, but often a sprinkling of common sense when working with areas such as networking can make a big difference.
Try to think about the data you send to the server and the impact it might have if it was intercepted.
Here are some example questions you could be asking yourself:
- Do I need to be sending {XYZ} data in this network call?
β You ideally should be sending the minimum amount of information required - Is {XYZ} dangerous in the wrong hands?
β What could an attacker do with the information should it be intercepted
β What is the worst-case scenario? - Does {XYZ} require appropriate authorization and/or authentication to use?
β Can the networking be locked down further using roles or identity verificationβΈ
I hope these examples kick start a conversation with yourself, your team and hopefully other engineers!
Next up π
In the upcoming posts within this series, we shall explore more of the OWASP Top 10 for Mobile. Next up is #4Β Insecure Authentication
Thanks π
Thanks as always for reading! I hope you found this post interesting, please feel free to tweet me with any feedback atΒ @Sp4ghettiCodeΒ and donβt forget to clap, like, tweet, share, star etc
Further Reading
- owasp-top-five Companion App
- M3: Insecure Communication : OWASP Foundation
- How CT Works: Certificate Transparency
- Be Afraid Of HTTP Public Key Pinning : Smashing Magazine
- Transport Layer Security (TLS) : Computerphile
Footnotes
[1] Assuming you remembered to add theΒ android.permission.INTERNET
Β permission… π¬
[2] βThe artist formerly known as Secure Sockets Layer (SSL)β π¨βπ€ β TLS mostly replaced SSL when it was deprecated in 2015
[3] Available as of Android 6.0 (API 23) but ignored in API 24+ if a network security file exists
[4] These certificates areΒ stillΒ commonly known by some as βSSL Certificatesβ, despite SSL being deprecated in favour of TLS
[5] Yes, I am afraid to say that in 2022 theΒ entire internetΒ hinges on this trust of third parties.Β Oh, and it does go wrong. Some nightmare fuel for you there, youβre welcome!
[6] The βdefault network security behaviourβ of apps targeting different versions is described in theΒ docs here.
[7] Well, βthis monthβ at the time of writing. It was also responsibly disclosed to the relevant security team of the company
[8] Keep an eye on my blog for more on this in futureβ¦
Thanks toΒ Omolara Adejuwon
This article was originally published onΒ proandroiddev.com on August 16, 2022