Configuration

Minimum Configuration

AppProtection can run without any configuration. However, in such settings, RASP features will only report security incidents to your delegate.

Reporting to the Malwarelytics web console is turned off in case of the minimal configuration.

Online Service

To see your protected devices and reported incidents in the Malwarelytics console, you need to provide valid credentials.

The Username, Password, and Signature Public Key can be obtained in the Get the SDK section. Note that these credentials are bound to your application Bundle ID. If you need to support multiple environments (Bundle IDs), you need different credentials for each environment.

Configuring the AppProtection

To enable AppProtection features in your app, you must create a properly configured instance of the AppProtectionService class and set the AppProtectionRaspDelegate to obtain callbacks.

You should implement the following configurations:

  • AppProtectionRaspConfig - Configures which RASP features are enabled and default actions for the detections.
  • AppProtectionOnlineConfig - Configuration of the online part of the AppProtection.
    • AppProtectionIdentificationConfig - Configures user identification. This can be changed later at runtime.
    • AppProtectionEventConfig - Configures which RASP events are emitted and sent to the back-end services.
    • AppProtectionCustomerGroupingConfig - Configuration of customer grouping and naming in the web application. For more details, visit Customer Grouping and Naming

Based on the configuration, the AppProtectionRaspDelegate receives updates about various RASP events.

Sample Integration

The AppSecurity swift class is a sample implementation over the AppProtectionService.

import Foundation
import WultraAppProtection

class AppSecurity: AppProtectionRaspDelegate {
    
    private let appProtection: AppProtectionService

    /// Creates AppSecurity instance
    /// - Parameter userId: ID of the user
    /// - Parameter deviceId: ID of the device
    init(userId: String?, deviceId: String?) {
    
        // Prepare the RASP feature configuration
        let raspConfig = AppProtectionRaspConfig(
            jailbreak: .exit("https://myurl.com/jalibreak-explained"), // exit on jailbroken phone
            debugger: .block, // block debugger
            reverseEngineeringTools: .notify, // let me know when user installed revers engineering tools
            httpProxy: .notify, // notify me via delegate when http proxy is enabled
            repackage:.exit([AppProtectionTrustedCert(withBase64EncodedString: "BASE_64_ENCODED_CERT")!], "https://myurl.com/repackage-explained"), // follow documentation how to obtain certificate string
            screenCapture: .hide(), // will hide the app contents when screen is captured (for example shared via airplay)
            vpnDetection: .notify, // notify me when VPN is connected or disconnected
            callDetection: .notify, // notify me when a call is detected
            appPresence: .notify([.KnownApps.anyDesk]) // notify me when AnyDesk application is installed. Note that you also have to specify the deeplink in your Info.plist (more in the feature documentation)
        )
        
        // Prepare the configuration for events
        let eventConfig = AppProtectionEventConfig(
            enableEventCollection: true, // enable event collection in general
            enableScreenshotTakenCollection: true // /track screenshot events in the Malwarelytics console on the server
        )
        
        // Prepare user identification
        let idConfig = AppProtectionIdentificationConfig(
            userId: userId,
            deviceId: deviceId
        )
        
    	 // Prepare the Online configuration
    	 let onlineConfig = onlineConfig = .inAppProtectionOnlineConfig(
            username: "$USERNAME",
            password: "$PASSWORD",
            signaturePublicKey: "$PUBKEY",
            clientIdentification: idConfig,
            eventsConfig: eventConfig,
            customerGroupingConfig: nil, // advanced feature, for more info see "Customer Grouping and Naming" section of the documentation
            environment: .production
        )
        
        // Prepare a configuration for service
        let config = AppProtectionConfig(
            raspConfig: raspConfig,
            onlineConfig: onlineConfig
        )

        // Create the Service
        self.appProtection = AppProtectionService(config: config)

        // Set the delegate to obtain RASP callbacks
        self.appProtection.rasp.addDelegate(self)
    }
    
    deinit {
        // When our AppSecurity class is being "destroyed", we want
        // to stop all features of the AppProtectionService.
        // To do so, we need to release all its assets before
        // the only reference that "holds it" is removed.
        
        self.appProtection.release()
    }

    /// Report in-app incident
    /// - Parameter incident: Incident that happened inside the app
    func reportIncident(_ incident: RaspIncident) {
        self.appProtection.online?.events.log(incident.appProtectionValue)
    }

    /// Call when client id changes (paired/unpaired the app).
    /// - Parameter deviceId: User id
    /// - Parameter deviceId: Device id
    func updateClientInfo(userId: String?, deviceId: String?) {
        self.appProtection.online?.clientIdentification.userId = userId
        self.appProtection.online?.clientIdentification.deviceId = deviceId
    }

    /// AppProtection resets the device indicator and starts registering it as a new device.
    func resetServiceId() {
        self.appProtection.online?.resetInstanceId()
    }

    // MARK: - AppProtectionRaspDelegate

    func debuggerDetected() {
        // react to debugger
    }

    func jailbreakDetected() {
        // react to jailbreak
    }

    func repackageDetected() {
        // react to repackage
    }

    func httpProxyEnabled() {
        // react to http proxy enabled
    }

    func userScreenshotDetected() {
        // react to user screenshot
    }

    func reverseEngineeringToolsDetected() {
        // react to reverse engineering tools
    }

    func systemPasscodeConfigurationChanged(enabled: Bool) {
        // react to system passcode change
    }

    func systemBiometryConfigurationChanged(enabled: Bool) {
        // react to biometry configuration changed
    }

    func screenCapturedChanged(isCaptured: Bool) {
        // react to screen capturing (casting to different device)
    }

    func vpnChanged(active: Bool) {
        // react to VPN state changes
    }

    func onCallChanged(isOnCall: Bool) {
        // on call status has changed
    }

    func installedAppsChanged(installedApps: [DetectableApp]) {
        // installed apps list has changed
    }
}

enum RaspIncident {
    case sslInvalidCert
    case deviceUnpaired
    case devicePaired
    case deviceBlocked
    case userIgnoredWeakPassphrase
    case passphraseChanged
    case biometryEnabled
    case biometryDisabled
    case authenticationFailed
    case authenticationSuccess

    var appProtectionValue: AppProtectionEvent {
        switch self {
        case .sslInvalidCert: return AppProtectionEvent.Network.sslInvalidCertificate
        case .deviceUnpaired: return AppProtectionEvent.Authentication.deviceUnpaired
        case .devicePaired: return AppProtectionEvent.Authentication.devicePaired
        case .deviceBlocked: return AppProtectionEvent.Authentication.deviceBlocked
        case .userIgnoredWeakPassphrase: return AppProtectionEvent.Authentication.userIgnoredWeakPassphrase
        case .passphraseChanged: return AppProtectionEvent.Authentication.passphraseChanged
        case .biometryEnabled: return AppProtectionEvent.Authentication.biometryEnabled
        case .biometryDisabled: return AppProtectionEvent.Authentication.biometryDisabled
        case .authenticationFailed: return AppProtectionEvent.Authentication.authenticationFailed
        case .authenticationSuccess: return AppProtectionEvent.Authentication.authenticationSuccess
        }
    }
}

Service Lifecycle

Be aware that the creation of 2 instances of AppProtectionService is considered to be a logical error and will result in application crash.

Before deiniting (removing all references to) the AppProtectionService object, you need to call release() to stop all its functionality. Deiniting without release will result in application crash.

Customer Grouping and Naming

The SDK allows passing custom values that are used to group data in the Malwarelytics web console application.
The configuration items in AppProtectionCustomerGroupingConfig add extra metadata that is passed into the web console.
The data allows to split data into groups and obtain different views on the data.

The data can be defined with:

let groupingConfig = AppProtectionCustomerGroupingConfig(
    sourceBundleId: "String", // optional
    appBundleId: "String", // optional
    audienceGroupId: "String" // optional
)

Limitations for the strings are the following:

  • Max length of sourceBundleId is 255 characters
  • Max length of appBundleId is 255 characters
  • Max length of audienceGroupId is 20 characters

Main grouping of the data is achieved with sourceBundleId . The value has to agree with the application credentials in the web console.
Extra granularity of data views is achieved with appBundleId.
The last option audienceGroupId is used to distinguish users from different customer systems such as “RETAIL”, “CORPORATE” and so on.

Last updated on Nov 01, 2024 (08:23) View product
Search

3.1.x

Malwarelytics for Apple