iOS SDK

Prev Next

Classic/VPC環境で利用できます。

iOSアプリのセキュリティのための App Safer iOS SDKの使用方法について説明します。SDKをインストールして環境を構成することで、App Saferを連携できます。

参考

App Saferを適用する全般的なサンプルコードは、サンプルコードでご確認ください。

SDKのインストールおよび環境設定

App Saferで提供する機能を利用するには、まず iOS SDKをインストールした後、環境を設定します。iOSアプリ用の App Saferのライブラリは1つのフレームワークで構成されており、Bitcode Enable/Disable環境のいずれもサポートします。設定方法は、次の通りです。

参考

Xcode 8.0以上の環境でビルドすることをお勧めします。

  1. ダウンロードした SDKを任意のディレクトリで圧縮を解凍します。
  2. プロジェクトの Bitcode設定を確認します。
    • パス: Build Settings > Build Options > Enable Bitcode
  3. App Saferフレームワークをプロジェクトに追加します。
    • パス: File > Add Files to "Your Project"... > Options > Copy items if needed選択 > AppSaferFramework.framework選択 > Addクリック
  4. Swiftを使う場合、Objective-Cとの互換性のために Bridging Headerを作成します。
    • ヘッダファイル作成: File > New File... > Header File選択 > プロジェクトのルート位置にファイル名 「AppSaferFramework-Bridging-Header.h」に設定
    • ヘッダファイルをビルド設定に追加: Build Settings > Swift Compiler - General > Objective-C Bridging Header > AppSaferFramework-Bridging-Header.hで次のコードを入力
      #ifndef AppSaferFramework_Bridging_Header_h
      #define AppSaferFramework_Bridging_Header_h
      
      #import <AppSaferFramework/AppSaferFramework.h>
      
      #endif /* AppSaferFramework_Bridging_Header_h */
      

デバッグ防止機能を適用

デバッグ防止機能は、SDKをインストールすると自動的に適用されます。もしデバッグが必要な場合、App Safer SDKを一時的に適用解除した状態で使用します。

キャプチャ遮断および検出機能の適用

App Safer SDKで提供するアプリプレビュー画面保護、スクリーンショット検出、録画およびミラーリング時の画面保護機能を適用するには、APIを呼び出す必要があります。

  • iOS 13.0未満: AppDelegateでアプリのライフサイクルに合わせて App Safer APIを呼び出し
  • iOS 13.0以上: SceneDelegateでアプリのライフサイクルに合わせて App Safer APIを呼び出し

APIを呼び出すユースケースは、次の通りです。
selectorを登録すると、キャプチャイベントの検出時に callbackを受信して希望する動作を実行できます。

AppDelegate (Swift)
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    @objc func didDetectCapture() -> Void  {
        print("[DETECT] Detected Screenshot in AppDelegate");
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        AppSafer.registerScreenProtectionObserver(window, observer: self, selector: #selector(didDetectCapture))
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        AppSafer.preventScreenshot(window, isInvisible: 0)
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        AppSafer.preventScreenshot(window, isInvisible: 1)
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        AppSafer.preventScreenshot(window, isInvisible: 0)
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        AppSafer.preventScreenshot(window, isInvisible: 1)
    }
}
AppDelegate (Objective-C)
#import "AppDelegate.h"
#import <AppSaferFramework/AppSaferFramework.h>

@interface AppDelegate ()
@end

@implementation AppDelegate

- (void)didDetectCapture {
    NSLog(@"[DETECT] Detected Screenshot in AppDelegate");
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey,id> *)launchOptions {
    [AppSafer registerScreenProtectionObserver:_window observer:self selector:@selector(didDetectCapture)];
    
    return YES;
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    [AppSafer preventScreenshot:_window isInvisible:false];
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    [AppSafer preventScreenshot:_window isInvisible:false];
}

- (void)applicationWillResignActive:(UIApplication *)application {
    [AppSafer preventScreenshot:_window isInvisible:true];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [AppSafer preventScreenshot:_window isInvisible:true];
}
@end
SceneDelegate (Swift)
import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    @objc func didDetectCapture() -> Void  {
        print("[DETECT] Detected Screenshot in AppDelegate");
    }
    
    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()
            
            AppSafer.registerScreenProtectionObserver(window, observer: self, selector: #selector(didDetectCapture))
        }
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        AppSafer.preventScreenshot(window, isInvisible: 0)
    }

    func sceneWillResignActive(_ scene: UIScene) {
        AppSafer.preventScreenshot(window, isInvisible: 1)
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        AppSafer.preventScreenshot(window, isInvisible: 0)
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        AppSafer.preventScreenshot(window, isInvisible: 1)
    }
}

SceneDelegate (Objective-C)
#import "SceneDelegate.h"
#import <AppSaferFramework/AppSaferFramework.h>

@interface SceneDelegate ()
@end

@implementation SceneDelegate

- (void)didDetectCapture {
    NSLog(@"[DETECT] Detected Screenshot in SceneDelegate");
}

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions API_AVAILABLE(ios(13.0)) {
    [AppSafer registerScreenProtectionObserver:_window observer:self selector:@selector(didDetectCapture)];
}

- (void)sceneWillEnterForeground:(UIScene *)scene API_AVAILABLE(ios(13.0)) {
    [AppSafer preventScreenshot:_window isInvisible:false];
}

- (void)sceneDidBecomeActive:(UIScene *)scene API_AVAILABLE(ios(13.0)) {
    [AppSafer preventScreenshot:_window isInvisible:false];
}

- (void)sceneWillResignActive:(UIScene *)scene API_AVAILABLE(ios(13.0)) {
    [AppSafer preventScreenshot:_window isInvisible:true];
}

- (void)sceneDidEnterBackground:(UIScene *)scene API_AVAILABLE(ios(13.0))  {
    [AppSafer preventScreenshot:_window isInvisible:true];
}

@end

提供 API

App Safer APIは2つのパッケージで提供され、各パッケージで呼び出せる APIは、次の通りです。

  • AppSafer
名前 説明
initAppSafer AppSaferを使用するために初期化
checkTampering リアルタイムセキュリティ検出
  • Jailbreak検出
  • Simulator検出
  • Debugging検出
  • Memory Tampered検出
  • Unauthorized Signature検出
setUserId ユーザー識別子設定
  • AppSaferDelegate
    • 非同期で動作する Callback関数です。
    • 結果処理は AppSaferDelegateを通じて委任されます。
    • 検査結果を受け取るためには AppSaferDelegateを実装した後、initAppSafer関数を使って登録する必要があります。
    • Swiftを使用する場合、structではない classに実装する必要があり、AppSaferDelegateと NSObjectをすべて追加する必要があります。
名前 要否 説明
appSaferDidInitFinish 必須 App Saferの初期化結果確認
appSaferDidCheckTamperingFinish 必須 checkTampering関数の実行結果確認
appSaferDetectedJailbreak 任意 デバイスの脱獄行為検出時に呼び出し
appSaferDetectedSimulator 任意 デバイスが仮想マシンで実行中であることを検出時に呼び出し
appSaferDetectedDebugging 任意 デバッグ行為検出時に呼び出し
appSaferDetectedMemoryTampered 任意 アプリのメモリ改ざん検出時に呼び出し

initAppSafer

App Saferは初期化に成功することで使用できるようになります。App Saferを初期化するには、以下のコードを使用します。
ログの送信に必要な情報およびグローバル変数として使われる変数が初期化されます。

  • 初期化の成否を受け取るためには、AppSaferDelegateを実装する必要があります。
func initAppSafer(_ delegate: AppSaferDelegate!, serviceCode: String!, key appsaferKey: String!) -> Int32
- (int) initAppSafer:(id<AppSaferDelegate>)delegate serviceCode:(NSString *)serviceCode key:(NSString *)appsaferKey
  • パラメータ

    パラメータ 説明
    delegate AppSaferDelegateが実装されたインスタンス
    serviceCode App Saferを利用するためのコード
    NAVERクラウドプラットフォームのユーザーは必ず「ncloud」を転送
    appsaferKey コンソールでアプリ登録時に作成された App Safer Key値
  • 戻り値

    戻り値 説明
    SUCCESS(0) 成功
    FAIL(-1) 失敗
  • ユースケース

    struct ContentView: View {
        func initAppSaferExample() {
           // APP_SAFER_KEY generated when registering an app to the Console
           let result = AppSafer().initAppSafer(AppSaferDelegator.delegator, serviceCode: "ncloud", key: "<APP_SAFER_KEY>")
    
           NSLog("initAppSafer() result: %d", result);
    
           if(result == SUCCESS) {
                 // init success
           } else if(result == FAIL) {
                 // init fail
           }
        }
    
        var body: some View {
           Button("initAppSafer") {
                 initAppSaferExample()
           }
        }
    }
    
    #import <AppSaferFramework/AppSaferFramework.h>
    
    @implementation ViewController
    
    - (IBAction)initAppSaferExample:(id)sender {
        AppSafer *appSafer = [[AppSafer alloc] init];
    
        int res = FAIL;
        if(appSafer != nil) {
           // APP_SAFER_KEY generated when registering an app to the Console
           res = [appSafer initAppSafer:self serviceCode:@"ncloud" key:@"<APP_SAFER_KEY>"];
    
           NSLog(@"initAppSafer() result: %d", res);
    
           if(res == SUCCESS) {
                 // init success
           }
        }
    }
    

checkTampering

リアルタイムセキュリティ検出機能を実行するには、以下のコードを使用します。

func checkTampering()
- (int)checkTampering
  • 戻り値

    戻り値 説明
    SUCCESS(0) 検査開始成功
    FAIL(-1) 検査開始失敗
    BLOCK(2) セキュリティポリシーの違反により遮断
    BEFOREINIT(3) App Saferが初期化されない
  • ユースケース

    struct ContentView: View {
        func checkTamperingExample() {
            let result = AppSafer().checkTampering()
    
            switch(result) {
            case FAIL:
                print("Failed to check tampering")
                break
            case SUCCESS:
                print("Check Tampering Success")
                break
            case BLOCK:
                print("Device is blocked")
                break
            case BEFOREINIT:
                print("AppSafer is not initialized")
                break
            default:
                break
            }
        }
    
        var body: some View {
            Button("checkTampering") {
                checkTamperingExample()
            }
        }
    }
    
    #import <AppSaferFramework/AppSaferFramework.h>
    
    @implementation ViewController
    
    - (IBAction)checkAppSafer:(id)sender {
        AppSafer *appSafer = [[AppSafer alloc] init];
    
        if(appSafer != nil) {
            int res = [appSafer checkTampering];
    
            switch(res) {
                case FAIL:
                    NSLog(@"Failed to check tampering");
                    break;
                case SUCCESS:
                    NSLog(@"Check Tampering Success");
                    break;
                case BLOCK:
                    NSLog(@"Device is blocked");
                    break;
                case BEFOREINIT:
                    NSLog(@"AppSafer is not initialized");
                    break;
            }
        } else {
            NSLog(@"AppSafer is nil");
        }
    }
    
    @end
    

setUserId

初期化および検出イベントの発生時に App Saferサーバに送信されるログにユーザー識別子を含むには、以下のコードを使用します。

func setUserId(_ userId: String!) -> Int32
- (int)setUserId:(NSString *)userId
  • パラメータ

    パラメータ 説明
    userId ユーザー識別子
  • 戻り値

    戻り値 説明
    SUCCESS(0) 設定成功
    FAIL(-1) 設定失敗
  • ユースケース

    struct ContentView: View {
        func setUserIdExample(_ userId: String) {
           print("setUserId(\(userId))")
    
           let result = AppSafer().setUserId(userId)
    
           switch(result) {
           case FAIL:
                 print("Failed to set userId: \(userId)")
                 break
           case SUCCESS:
                 print("setUserId() Success: \(userId)")
                 break
           default:
                 break
           }
        }
    
        var body: some View {
           Button("setUserId") {
                 setUserIdExample("ExampleUserId")
           }
        }
    }
    
    #import <AppSaferFramework/AppSaferFramework.h>
    
    @implementation ViewController
    
    - (IBAction)setUserId:(id)sender {
        AppSafer *appSafer = [[AppSafer alloc] init];
    
        if(appSafer != nil) {
           NSLog(@"setUserId(%@)", [self.useridText text]);
    
           int res = [appSafer setUserId:[self.useridText text]];
    
           switch(res) {
                 case FAIL:
                    NSLog(@"Failed to set userId");
                    break;
                 case SUCCESS:
                    NSLog(@"setUserId Success");
                    break;
           }
        } else {
           NSLog(@"AppSafer is nil");
        }
    }
    

appSaferDidInitFinish

initAppSafer関数の呼び出し後、初期化結果を転送するために下記の関数が呼び出されます。

func appSaferDidInitFinish(_ result: Int32)
- (void)appSaferDidInitFinish:(int)result
  • パラメータ

    パラメータ 説明
    SUCCESS(0) 初期化成功
    FAIL(-1) 初期化失敗
    BLOCK(2) セキュリティポリシー違反により遮断
  • ユースケース

    func appSaferDidInitFinish(_ result: Int32) {
        print("appSaferDidInitFinish result: \(result)");
        if(result == BLOCK) {
           print("Device is blocked!");
           // add to exit application logic
        }
    }
    
    #import <AppSaferFramework/AppSaferFramework.h>
    
    @implementation ViewController
    
    - (void)appSaferDidInitFinish:(NSUInteger)result msg:(NSString *)message {
        NSLog(@"appSaferDidInitFinish result: %d", result);
        if(result == BLOCK) {
           NSLog(@"Device is blocked!");
           // add to exit application logic
        }
    }
    

appSaferDidCheckTamperingFinish

checkTampering関数の実行結果を転送するために下記の関数が呼び出されます。

func appSaferDidCheckTamperingFinish(_ result: Int32)
- (void)appSaferDidCheckTamperingFinish:(int)result
  • パラメータ

    パラメータ 説明
    FAIL(-1) 検査失敗
    SAFE(0) イベントが検出されない
    DETECT(1) イベント検出
    BLOCK(2) 遮断済み
  • ユースケース

    func appSaferDidCheckTamperingFinish(_ result: Int32) {
        print("appSaferDidCheckTamperingFinish result: " + (
                 result == FAIL   ? "FAIL" :
                 result == SAFE   ? "SAFE" :
                 result == DETECT ? "DETECT" :
                 result == BLOCK  ? "BLOCK": "UNKNOWN"))
    
        if(result == BLOCK) {
           print("Device is blocked!")
           // add to exit application logic
        }
    }
    
    #import <AppSaferFramework/AppSaferFramework.h>
    
    @implementation ViewController
    
    - (void)appSaferDidCheckTamperingFinish:(int)result {
        NSLog(@"appSaferDidCheckTamperingFinish result: %@",
              result == FAIL   ? @"FAIL" :
              result == SAFE   ? @"SAFE" :
              result == DETECT ? @"DETECT" :
              result == BLOCK  ? @"BLOCK": @"UNKNOWN");
    
        if(result == BLOCK) {
           NSLog(@"Device is blocked!");
           // add to exit application logic
        }
    }
    

appSaferDetectedJailbreak

デバイスの脱獄が検出されると、以下の関数が呼び出されます。checkTampering関数の動作が完了していない場合でも、結果を受け取りたいときに使用できます。

func appSaferDetectedJailbreak()
- (void)appSaferDetectedJailbreak
  • ユースケース

    func appSaferDetectedJailbreak() {
        print("[DETECT] appSaferDetectedJailbreak");
    }
    
    #import <AppSaferFramework/AppSaferFramework.h>
    
    @implementation ViewController
    
    - (void)appSaferDetectedJailbreak {
        NSLog(@"[DETECT] appSaferDetectedJailbreak");
    }
    

appSaferDetectedSimulator

アプリが仮想マシンで実行中であることが検出されると、以下の関数が呼び出されます。checkTampering関数の動作が完了していない場合でも、結果を受け取りたいときに使用できます。

func appSaferDetectedSimulator()
- (void)appSaferDetectedSimulator
  • ユースケース

    func appSaferDetectedSimulator() {
        print("[DETECT] appSaferDetectedSimulator");
    }
    
    #import <AppSaferFramework/AppSaferFramework.h>
    
    @implementation ViewController
    
    - (void)appSaferDetectedSimulator {
        NSLog(@"[DETECT] appSaferDetectedSimulator");
    }
    

appSaferDetectedDebugging

デバイスでデバッグが検出されると、以下の関数が呼び出されます。checkTampering関数の動作が完了していない場合でも、結果を受け取りたいときに使用できます。

func appSaferDetectedDebugging()
- (void)appSaferDetectedDebugging
  • ユースケース

    func appSaferDetectedDebugging() {
        print("[DETECT] appSaferDetectedDebugging");
    }
    
    #import <AppSaferFramework/AppSaferFramework.h>
    
    @implementation ViewController
    
    - (void)appSaferDetectedDebugging {
        NSLog(@"[DETECT] appSaferDetectedDebugging");
    }
    

appSaferDetectedMemoryTampered

メモリ改ざんが検出されると、以下の関数が呼び出されます。checkTampering関数の動作が完了していない場合でも、結果を受け取りたいときに使用できます。

func appSaferDetectedMemoryTampered()
- (void)appSaferDetectedMemoryTampered
  • ユースケース

    func appSaferDetectedMemoryTampered() {
        print("[DETECT] appSaferDetectedMemoryTampered");
    }
    
    #import <AppSaferFramework/AppSaferFramework.h>
    
    @implementation ViewController
    
    - (void)appSaferDetectedMemoryTampered {
        NSLog(@"[DETECT] appSaferDetectedMemoryTampered");
    }