Screen Caching

Screen Caching is another of those vulnerabilities nobody is paying attention to, and this one is quite important.

As an example, even most bank applications are usually ‘vulnerable’ to this issue (most of mine are). And this is a reality even for those focusing on security, like web based only banks.

So what is screen caching?

Screen caching is a mobile vulnerability, caused due to a performance/usability feature present in mobile OS’s.

Let’s see an example, you’re navigating in your bank account through the mobile app, then you send the application to background and go on with your life.

When you grab back your phone and eventually open the “Recent Apps” screen you’ll see there the bank’s application with the sensitive information like your bank account balance. This is specially bad if you are showing something to your friends on your phone, as they can easily see this private information.

How to Fix it

This is an intended behavior from iOS as well as Android, that take a snapshot of the application right before it is backgrounded, to be shown in the App Switcher (iOS) or “Recent App” screen (Android).

So a fix to this issue is to hide the important fields just before the app enters background.

There are a few ways to do this, but these are the 2 most common:

  • Just before the app enters background open a new view. This is usually done with just the app logofor that. When the app is opened again, hide the screen
  • Hide the fields with sensitive information when the application is being backgrounded. Revert the operation when opening back.

Android

Android has native ways to add this protection, being the easiest one, showing a blank screen by specifying a secure flag

This can be done by registering the relevant activities as secure in the onCreate method like so:

getWindow().setFlags(
   WindowManager.LayoutParams.FLAG_SECURE, 
   WindowManager.LayoutParams.FLAG_SECURE
);
no screen caching protection
screen caching protection

iOS

For iOS the easiest way to accomplish this is by using the methods ‘sceneWillResignActive’ and ‘sceneDidBecomeActive’ from AppDelegate/SceneDelegate.


import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?
    var screenCachingProtection: UIView!
    
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        let contentView = ContentView()

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
            
            self.screenCachingProtection = UIView.init(frame: window.frame )
            self.screenCachingProtection?.backgroundColor = UIColor.white
        }
    }

    func sceneDidDisconnect(_ scene: UIScene) {}

    func sceneDidBecomeActive(_ scene: UIScene) {
        self.screenCachingProtection?.removeFromSuperview()
    }

    func sceneWillResignActive(_ scene: UIScene) {
        self.window?.addSubview(self.screenCachingProtection!)
    }

    func sceneWillEnterForeground(_ scene: UIScene) {}

    func sceneDidEnterBackground(_ scene: UIScene) {}

}
Screen caching vulnerable app
Screen caching fixed app

You can use this as well to show a splash screen or something similar.

This code only works for UIKit App Delegate’s App lifecycle. If you chose to manage the app lifecycle with SwiftUI I’ll update this post with the code for that in the future

Another nice trick for iOS is to blur the background. There’s a nice comment on StackOverflow for that.

ClZHaGxVMlZqZFhKcGRIbFdZWFZzZEVobGNrWnZjbGx2ZFZSb1pWTmxZM1ZwZEhsV1lYVnNkRWhsY21WR2IzSlpiM1ZVYUdWVFkzVnlhWFI1Vm1GMWJIUklaWEpsUm05eVdXOTFWR2hsVTJWamRYSnBkSGxXWVhWc2RFaGxaVVp2Y2xsdmRWUm9aVk5qZFhKcGRIbFdZWFZzZEVobGNtVkdiM0paYjNWVWFGTmxZM1Z5YVhSNVZtRjFiSFJJWlhKbFJtOXlXVzkxVkdobFUyVmpkWEpwZEhsV1lYVnNkRWhsY21WdmNsbHZkVlJvWlZObFkzVnlhWFI1Vm1GMWJIUkljbVZHYjNKWmIzVlVhR1ZUWldOMWNuUjVWbUYxYkhSSVpYSmxSbTl5V1c5MVZHaGxVMlZqZFhKcGRIbFdZWFZzZEVobGNrWnZjbGx2ZFZSb1pWTmxZM1Z5YVhSNVZtRjFiSFJJWlhKbFJtOXlXWFZVYUdWVFpXTjFjbWwwZVZaaGRXeDBTR1Z5WlVaeVdXOTFhR1ZUWldOMWNtbDBlVlpoZFd4MFNHVnlaVVp2Y2xsdmRWUm9aVk5sWTNWeWFYUjVWbUYxYkhSSVpYSmxiM0paYjNWVWFHVlRaV04xY21sMGVXRjFiSFJJWlhKbFJtOXlXVzkxVkdobFUyVmpkWEpwZEhsV1lYVnNkRWhsY2tadmNsbHZkUT09