iOS – Secure app sensitive information

Today I want to share a fresh new Swift Package SDK that helps you to hide sensitive informations on your app, like banking apps, in a easy way!

You’ll be notified via callback (optional) when a defined rule occur, and apply the right custom protection you prefer or simply use the integrated blur that cover your app automatically.


Available protections

While writing this post, the SDK provide these protections callbacks:

QuickTime screen recordingiOS avoid QuickTime recording
iOS screen recordingiOS block screen recording
iOS native Airplay / MirroringiOS prevent block mirroring
Background app screenshot cacheiOS avoid cache background app screenshot
User taken screenshotsiOS detect prevent screenshots

How it works

Simply, add a view on top of your root window, in order to hide sensitive content behind.

Imagine that you app is this one:

When one of the defined rules to apply is recognized, a custom view or a blurred view can appear on top:

You can handle more of these rules, the code is on Github, feel free to open merge requests.

You can also apply a custom behavior when detected (show an alert, send an API request, or what you prefer…).


Code usage.

Add the repo directly in Swift Package Manager through XCode and import the SDK (generally in SceneDelegate or AppDelegate, because you need the window):

import ScreenSecuritySDK

Next in your sceneWillConnect, initialize the SDK:

var screenSecurity: ScreenSecurity?
[...]
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    screenSecurity = ScreenSecurity( window! )
}

Creating security rules

Allowed types are defined in this enum:

case quickTime
case screenRecording
case mirroring
case screenCache
case screenshot

You can create the rules you prefer, in this way:

let mirroringRule = ScreenSecurityRules {
    $0.type = .mirroring
    $0.callback = self.mirrorDetected
}

In every rule you can add a type, that is mandatory and a callback that is optional and can be used inline or with a custom defined function (as you prefer).

// example as custom callback
var mirrorDetected: (Any?, Bool) -> Void = 
  { (arg: Any?, status: Bool) -> Void in
    print("mirrorDetected: \(status)")
}

// example of inline callback
let mirroringRule = ScreenSecurityRules {
    $0.type = .mirroring
    $0.callback = (arg: Any?, status: Bool) -> Void in {
	    print("mirrorDetected: \(status)")
    }
}

ScreenCache extra settings

In case you need the screenCache rule, you need also to add the sceneDelegate or appDelegate param:

let screenCacheRule = ScreenSecurityRules {
    $0.type = .screenCache
    $0.callback = self.screenCacheDetected
    $0.sceneDelegate = self // one of these
    $0.appDelegate = self // one of these
}

You need also to inform the SDK when the app-lifecycle methods are called, and you need to call the screenSecurity?.listen() method in these delegates:

func sceneDidBecomeActive(_ scene: UIScene) {
    screenSecurity?.listen(type: .didBecomeActive)
}

func sceneWillResignActive(_ scene: UIScene) {
    screenSecurity?.listen(type: .willResignActive)
}

func sceneWillEnterForeground(_ scene: UIScene) {
    screenSecurity?.listen(type: .willEnterForeground)
}

func sceneDidEnterBackground(_ scene: UIScene) {
    screenSecurity?.listen(type: .didEnterBackground)
}
If you need to go deep on how iOS save automatically the screenshot of your app when is in background, take a read here: https://www.albertopasca.it/whiletrue/ios-data-leakage-app-background-cache/ .

Composing rules

Now, create the rules your prefer and next configure the SDK passing the rules and the settings needed:

var rules = [ScreenSecurityRules]()
rules = [
    mirroringRule,
    quickTimeRule,
    screenRecordingRule,
    screenCacheRule,
    screenshotRule
]

and pass it to initializer

screenSecurity?.configure(rules: rules, autoBlur: true)

The configure method take as parameters:

rules: your custom created rules

autoBlur: to use integrated automatic blur

customView: UIVIew, if you want to use your custom view + logo


Add a custom view instead of blur

If you prefer to use your custom view, you can pass it creating a new UIView, simply:

let customView = UIView(frame: self.window!.bounds)
customView.backgroundColor = .red.withAlphaComponent(0.9)

let image = UIImage(named: "logo")!
let midX = UIScreen.main.bounds.midX - 200 / 2
let midY = UIScreen.main.bounds.midY - 100
let imageView = UIImageView(frame: CGRect(
    x: midX,
    y: midY,
    width: 200,
    height: 100))
imageView.image = image
imageView.contentMode = .scaleAspectFit
imageView.backgroundColor = .clear
customView.addSubview(imageView)

screenSecurity?.configure(rules: rules, autoBlur: false, customOverlay: customView)

Build and run.


Open points:

  • user screenshots actually are not blocked, only informed. Hint: if your app use the camera roll, you can delete latest taken picture automatically (that is the screenshot)… 🤫
  • SDK is under development

Merge requests are welcome!


Repo GitHub / Swift Package Manager here: https://github.com/elpsk/ScreenSecuritySDK

Inspired by: https://screenshieldkit.com

App cache: https://www.albertopasca.it/whiletrue/ios-data-leakage-app-background-cache/)

 

Alberto Pasca

Software engineer @ Pirelli & C. S.p.A. with a strong passion for mobile  development, security, and connected things.