Threat-Events™, In-App Threat Intelligence in Unity Apps with Native iOS
This guide walks you through integrating Appdome’s Threat-Events™ into your Unity applications, offering a step-by-step approach to enhancing mobile app security.
What are Threat-Events?
Appdome Threat-Events is a robust threat-intelligence framework for iOS apps. It consists of three elements: a Threat Event, the data from each Threat Event, and the Threat-Score™.
Threat-Events streamlines the process for mobile developers by enabling them to register for, listen to, and consume real-time attack and threat data, courtesy of Appdome’s suite of mobile app security, anti-fraud, and mobile anti-bot protection measures. This functionality offers mobile app developers the ability to customize business logic and user experience based on the user’s risk profile and the specific attack or threat presented but also ensures that their mobile application workflows are aware of attacks and threats. Furthermore, it facilitates the passing of threat data to other systems of record, such as app servers, mobile fraud analysis systems, SIEMs, and other data collection points.
Threat Events enable iOS applications to adapt and respond to mobile app attacks and threats in real time, ensuring the safety of users, data, and transactions.
Mobile Application Threat-Events vs. Threat-Scores
Appdome Threat Events can be used as a stand-alone implementation in Unity Apps or in combination with Threat Scores. Threat Events provide in-app notifications of each attack or threat, as well as the metadata associated with the attack. Threat Scores provide the mobile developer with a Threat Event event score and the combined (aggregated) mobile end-user risk score at the time of the notification.
Prerequisites
Before implementing Threat-Events or Threat-Scores in your Unity App, ensure that the following conditions are met:
- Appdome account (create a free Appdome account here)
- Mobile App (.ipa for iOS)
- Appdome account class – Appdome DEV or higher.
- Mobile Application Source Code.
- Signing Credentials (e.g., signing certificates and provisioning profile) – see Signing Secure iOS apps.
- Threat-Events and/or Threats have been enabled ( turned ON) for specific protection.
- You are using the correct identifiers for the Threat-Events for each protection.
Note: The specific identifiers for each Threat Event and Threat Score are in the knowledge base article associated with each protection.
iOS
- Enable Threat-Events
- Select the checkbox next to Threat-Events for the desired runtime protection.
- This enables (turns ON) Threat-Events for that feature.
- Enable Threat Scores
- Click the up/down arrow associated with Threat Scores to assign a specific score to each protection.
- Assign a specific threat score between 1 and 999 to each protection.
Note: Threat-Events and Threat Scores can be used with or in place of server-based mobile anti-fraud solutions.
The figure below illustrates the locations of Threat Events and Threat Scores for various protections available on Appdome, including runtime mobile app security, anti-fraud, anti-malware, mobile antibot, and more.
Communicating with Native Platforms in Unity
To communicate with native iOS platforms in Unity, you typically use native plugins or platform-specific APIs. Here’s a more detailed guide:
- Native Plugins: Write code in Objective-C/Swift for iOS activity outside Unity. Connect it with Unity using Unity’s native plugin system. You can then call this code from Unity and receive messages back.
- Unity’s APIs: Unity offers built-in APIs (`UnityEngine.iOS`) to access device features directly from Unity scripts.
- Third-Party Packages: Explore Unity Package Manager or the Asset Store for pre-built solutions that simplify communication with iOS platforms.
- Asset Store Plugins: Check the Unity Asset Store for plugins that provide ready-made solutions for native platform integration.
Pick the method that suits your project’s needs and your team’s skills. Each method has its own pros and cons.
Code Snippet Required for Using Threat-Events with Unity Apps with Native iOS
Native iOS Plugin:
- Create a new Objective-C file named IOSThreatEventReceiver.mm.
- Add the following lines, which define the IOSRegisterReceiver native Objective-C function pointer that will register to a Threat Event:
#import <Foundation/Foundation.h> typedef void (*ThreatEventCallback)(const char *message); @interface IOSThreatEventReceiver : NSObject @end @implementation IOSThreatEventReceiver +(void) registerReceiver : (ThreatEventCallback) threatEventCallback name: (NSString *) eventName { [[NSNotificationCenter defaultCenter] addObserverForName:eventName object:nil queue:nil usingBlock:^(NSNotification *note) { NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[note userInfo] options:NSJSONWritingPrettyPrinted error:nil]; NSString *jsonDataStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; threatEventCallback([jsonDataStr UTF8String]); }]; } @end extern "C" { void IOSRegisterReceiver(ThreatEventCallback threatEventCallback, const char *eventName) { [IOSThreatEventReceiver registerReceiver:threatEventCallback name:[NSString stringWithUTF8String: eventName]]; } }
- Place the IOSThreatEventReceiver.mm. in the Assets/Plugins/iOS folder.
C# Scripts:
- Create a new C# script named ThreatEventsimp.cs.
- Add the following lines, which add Appdome Threat-Events registration to the Start()method (using the native iOS callback IOSRegisterReceiver):
- Place this script in Assets/Scripts.
using System.Runtime.InteropServices; using Newtonsoft.Json.Linq; using UnityEngine; using UnityEngine.UI; public class ThreatEventsImp : MonoBehaviour { // delegate declaration delegate void ThreatEventCallback(string jsonDataStr); // delegate instance static private ThreatEventCallback threatEventCallback; // iOS native function pointer [DllImport("__Internal")] private static extern void IOSRegisterReceiver(ThreatEventCallback threatEventCallback, string eventName); void Start() { // initialize threat event callback - OnThreatEventCallback will be called when the threat event occurs threatEventCallback = new ThreatEventCallback(OnThreatEventCallback); // register threat events to the callback IOSRegisterReceiver(threatEventCallback, "BlockedKeyboardEvent"); IOSRegisterReceiver(threatEventCallback, "BlockedClipboardEvent"); IOSRegisterReceiver(threatEventCallback, "BlockedScreenCaptureEvent"); IOSRegisterReceiver(threatEventCallback, "JailbrokenDevice"); IOSRegisterReceiver(threatEventCallback, "SslCertificateValidationFailed"); IOSRegisterReceiver(threatEventCallback, "SslNonSslConnection"); IOSRegisterReceiver(threatEventCallback, "SslServerCertificatePinningFailed"); IOSRegisterReceiver(threatEventCallback, "UrlWhitelistFailed"); IOSRegisterReceiver(threatEventCallback, "SslIncompatibleCipher"); IOSRegisterReceiver(threatEventCallback, "SslIncompatibleVersion"); IOSRegisterReceiver(threatEventCallback, "SslInvalidCertificateChain"); IOSRegisterReceiver(threatEventCallback, "SslInvalidMinRSASignature"); IOSRegisterReceiver(threatEventCallback, "SslInvalidMinECCSignature"); IOSRegisterReceiver(threatEventCallback, "SslInvalidMinDigest"); IOSRegisterReceiver(threatEventCallback, "AppIntegrityError"); } [AOT.MonoPInvokeCallback(typeof(ThreatEventCallback))] static void OnThreatEventCallback(string jsonDataStr) { var userInfo = JObject.Parse(jsonDataStr); string blocked; string keyboard; string message; string timestamp; string deviceID; string deviceModel; string osVersion; string kernelInfo; string deviceManufacturer; string fusedAppToken; string carrierPlmn; string internalError; string threatEventDetailedMessage; string certificateSHA1; string certificateCN; string host; string incompatibleCipherId; string incompatibleSslVersion; string reason; string eventID = (string)userInfo["externalID"]; switch (eventID) { case "BlockedKeyboardEvent": // "true" or "false" blocked = (string)userInfo["blocked"]; // Package of the keyboard keyboard = (string)userInfo["keyboard"]; // message specified in the fusion set message = (string)userInfo["message"]; // UNIX timestamp when event happened timestamp = (string)userInfo["timestamp"]; // Unique device identifier deviceID = (string)userInfo["deviceID"]; // Mobile device model deviceModel = (string)userInfo["deviceModel"]; // Mobile device OS version osVersion = (string)userInfo["osVersion"]; // Kernel information kernelInfo = (string)userInfo["kernelInfo"]; // Mobile device manufacturer deviceManufacturer = (string)userInfo["deviceManufacturer"]; // Build ID fusedAppToken = (string)userInfo["fusedAppToken"]; // Carrier identity number (PLMN code) carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "BlockedClipboardEvent": blocked = (string)userInfo["blocked"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "BlockedScreenCaptureEvent": message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "JailbrokenDevice": // Opaque identifier of root detection method internalError = (string)userInfo["internalError"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "SslCertificateValidationFailed": // A detailed message describing the detection threatEventDetailedMessage = (string)userInfo["DeveventDetailedErrorMessage"]; // The certificate sha1 fingerprint certificateSHA1 = (string)userInfo["certificateSHA1"]; // The certificate CN (common name) certificateCN = (string)userInfo["certificateCN"]; // The host that triggered the detection host = (string)userInfo["host"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "SslNonSslConnection": threatEventDetailedMessage = (string)userInfo["DeveventDetailedErrorMessage"]; host = (string)userInfo["host"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "SslServerCertificatePinningFailed": threatEventDetailedMessage = (string)userInfo["DeveventDetailedErrorMessage"]; certificateSHA1 = (string)userInfo["certificateSHA1"]; certificateCN = (string)userInfo["certificateCN"]; host = (string)userInfo["host"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "UrlWhitelistFailed": message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "SslIncompatibleCipher": // The Incompatible Cipher Id incompatibleCipherId = (string)userInfo["incompatibleCipherId"]; host = (string)userInfo["host"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "SslIncompatibleVersion": // The Incompatible SSL/TLS version incompatibleSslVersion = (string)userInfo["incompatibleSslVersion"]; host = (string)userInfo["host"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "SslInvalidCertificateChain": threatEventDetailedMessage = (string)userInfo["DeveventDetailedErrorMessage"]; certificateSHA1 = (string)userInfo["certificateSHA1"]; certificateCN = (string)userInfo["certificateCN"]; host = (string)userInfo["host"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "SslInvalidMinRSASignature": threatEventDetailedMessage = (string)userInfo["DeveventDetailedErrorMessage"]; certificateSHA1 = (string)userInfo["certificateSHA1"]; certificateCN = (string)userInfo["certificateCN"]; host = (string)userInfo["host"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "SslInvalidMinECCSignature": threatEventDetailedMessage = (string)userInfo["DeveventDetailedErrorMessage"]; certificateSHA1 = (string)userInfo["certificateSHA1"]; certificateCN = (string)userInfo["certificateCN"]; host = (string)userInfo["host"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "SslInvalidMinDigest": threatEventDetailedMessage = (string)userInfo["DeveventDetailedErrorMessage"]; certificateSHA1 = (string)userInfo["certificateSHA1"]; certificateCN = (string)userInfo["certificateCN"]; host = (string)userInfo["host"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; case "AppIntegrityError": // The detected tampered component reason = (string)userInfo["reason"]; message = (string)userInfo["message"]; timestamp = (string)userInfo["timestamp"]; deviceID = (string)userInfo["deviceID"]; deviceModel = (string)userInfo["deviceModel"]; osVersion = (string)userInfo["osVersion"]; kernelInfo = (string)userInfo["kernelInfo"]; deviceManufacturer = (string)userInfo["deviceManufacturer"]; fusedAppToken = (string)userInfo["fusedAppToken"]; carrierPlmn = (string)userInfo["carrierPlmn"]; // Respond to mobile app attacks and threats here break; default: Debug.Log("unknown event received " + eventID); break; } } }
Special Considerations
- Replace the event identifiers in your ThreatEventsImp according to the selections you made while fusing the application. To find the relevant Threat-Event context key, search for the specific feature via our knowledge base and navigate to the code sample section in the relevant article.
- You can stack multiple listeners for various events for comprehensive threat detection and response capabilities.
- Refer to the official documentation on Native iOS Plugin, BroadcastReceiver, and NSNotificationCenter for detailed information, advanced usage, and alternative implementation methods.
Meta-Data for Mobile Application Threat-Events and Threat-Scores
Below is the list of metadata that can be associated with each mobile application, Threat-Event, and Threat-Score in Unity Apps.
Threat-Event Context Keys
message
Message displayed for the user on event
failSafeEnforce
Timed enforcement against the identified threat
externalID
The external ID of the event which can be listened via Threat Events
osVersion
OS version of the current device
deviceModel
Current device model
deviceManufacturer
The manufacturer of the current device
fusedAppToken
The task ID of the Appdome fusion of the currently running app
kernelInfo
Info about the kernel: system name, node name, release, version and machine.
deviceID
Current device ID
reasonCode
Reason code of the occurred event
buildDate
Appdome fusion date of the current application
devicePlatform
OS name of the current device
updatedOSVersion
Is the OS version up to date
timeZone
Time zone
deviceFaceDown
Is the device face down
locationLong
Location longitude conditioned by location permission
locationLat
Location latitude conditioned by location permission
locationState
Location state conditioned by location permission
wifiSsid
Wifi SSID
wifiSsidPermissionStatus
Wifi SSID permission status
Some or all of the meta-data for each mobile application Threat-Event and Threat-Score can be consumed in Unity Apps at the discretion of the mobile developer and used, in combination with other mobile application data, to adapt the business logic or user experience when one or more attacks or threats are present.
Using Conditional Enforcement for Mobile Application Threat-Events and Threat-Scores
Conditional Enforcement is an extension to Appdome’s mobile application Threat-Event framework. By using conditional enforcement, developers can control when Appdome enforcement of each mobile application protection takes place or invoke backup, failsafe, and enforcement to any in-app enforcement used by the mobile developer.
Verifying Threat Events in Unity Apps
After you have implemented the required Threat-Event code in your Unity Apps, you can confirm that the Appdome protections in the Unity Apps properly recognize your Threat-Event implementation by reviewing the Certified Secure™ DevSecOps certificate for your build on Appdome.
In the Certified Secure DevSecOps certificate, an incorrect implementation of Threat Events in your mobile application is displayed, as shown below.
For information on how to retrieve the Certified Secure DevSecOps certification for your mobile application on Appdome, please visit the knowledge base article: Using Certified Secure™ Android & iOS Apps Build Certification in DevOps CI/CD
Related Articles
- Threat-Events™, In-App Threat Intelligence in Kotlin Apps
- Threat-Events™, In-App Threat Intelligence in Flutter Apps
- Threat-Events™, In-App Threat Intelligence in Native iOS Apps
- Threat-Events™, In-App Threat Intelligence in React Native Apps
- Threat-Events™, In-App Threat Intelligence in Swift Apps
- Threat-Events™, In-App Threat Intelligence in Maui, Xamarin Apps
- Implementing Threat Events – Best Practices
- How To Implement Threat-Events in Java
How Do I Learn More?
If you have any questions, please send them our way at support.appdome.com or via the chat window on the Appdome platform.
Thank you!
Thanks for visiting Appdome! Our mission is to secure every app on the planet by making mobile app security easy. We hope we’re living up to the mission with your project.