- 인쇄
- PDF
App Safer iOS 적용 방법
- 인쇄
- PDF
App Safer iOS는 네이버 클라우드 플랫폼이 제공하는 모바일 보안 솔루션으로서, 모바일 기기나 서비스에 위협이 되는 행위를 탐지하는 API를 제공합니다. iOS용 App Safer 라이브러리는 하나의 프레임워크로 구성되어 있으며, Bitcode Enable/Disable 환경을 모두 지원합니다.
App Safer iOS 특징
- Jailbreak 탐지
- Simulator 탐지
- Memory Tampered 탐지
- Unauthorized Signature 탐지
- Debugging 탐지
- Debugging 방지
- 캡처 방지
App Safer iOS 지원 환경
파일 이름 | OS 버전 |
---|---|
AppSaferFramework.framework | iOS 8.0 이상 |
App Safer iOS SDK 적용 가이드
AppSaferFramework를 적용하는 방법은 아래와 같습니다.
Xcode 8.0 이상의 환경에서 빌드를 권고합니다.
다운로드 받은 SDK를 임시 디렉토리에 압축 해제
프로젝트의
Bitcode
설정을 확인하고,AppSaferFramework
를 프로젝트에 추가Build Settings
>Enable Bitcode
확인File
>Add Files to "Your Project"...
>Options
>Copy items if needed
체크 >AppSaferFramework.framework
선택 >Add
(Swift Only)
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
입력
- AppSaferFramework-Bridging-Header.h
#ifndef AppSaferFramework_Bridging_Header_h
#define AppSaferFramework_Bridging_Header_h
#import <AppSaferFramework/AppSaferFramework.h>
#endif /* AppSaferFramework_Bridging_Header_h */
디버깅 방지 기능 적용 가이드
디버깅 방지 기능은 App Safer iOS SDK 적용 시 자동으로 적용됩니다.
만약 디버깅이 필요한 경우 App Safer iOS SDK를 일시적으로 적용하지 않은 상태에서 사용하시면 됩니다.
캡처 차단 및 탐지 적용 가이드
App Safer SDK는 캡처 차단 기능으로 앱 미리보기 화면 보호
, 스크린샷 탐지
, 녹화 및 미러링 시 화면 보호
기능을 제공하고 있습니다. 해당 기능을 적용하려면 iOS 13.0 미만에서는 AppDelegate에서 애플리케이션 생명주기에 맞춰 App Safer API 호출이 필요하며, iOS 13.0 이상에서는 SceneDelegate에서 애플리케이션 생명주기에 맞춰 App Safer API 호출이 필요합니다.
차단 및 탐지를 위해 아래 예제 처럼 App Safer 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
App Safer iOS API 목록
- AppSafer
API | 설명 |
---|---|
initAppSafer | AppSafer을 사용하기 위해 초기화 |
checkTampering | 실시간 보안 탐지
|
setUserId | 사용자 ID를 설정 |
- AppSaferDelegate
Delegate | 필수 | 설명 |
---|---|---|
appSaferDidInitFinish | Required | App Safer의 초기화 결과를 전달 받음 |
appSaferDidCheckTamperingFinish | Required | checkTampering 함수 수행이 완료되면 결과를 전달 |
appSaferDetectedJailbreak | Optional | Jailbreak 탐지 시점에 호출 |
appSaferDetectedSimulator | Optional | Simulator 탐지 시점에 호출 |
appSaferDetectedDebugging | Optional | Debugging 탐지 시점에 호출 |
appSaferDetectedMemoryTampered | Optional | Memory Tampered 탐지 시점에 호출 |
App Safer iOS API 설명
initAppSafer
App Safer를 사용하기 위해 초기화합니다. 로그를 전송하는 데 필요한 정보 및 전역으로 사용되는 변수를 초기화합니다.
- App Safer의 모든 API는 initAppSafer()가 성공적으로 호출된 후에 사용할 수 있습니다.
- 초기화 성공 여부를 전달받기 위해 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 서비스를 이용하기 위한 코드 네이버 클라우드 플랫폼 사용자는 반드시 'ncloud'를 전달 |
appsaferKey | 콘솔에서 앱 등록 시 생성된 appsaferKey값 |
반환 값
반환 값 | 설명 |
---|---|
SUCCESS(0) | 성공 |
FAIL(-1) | 실패 |
예제
Swift
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()
}
}
}
Objective-C
#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
실시간 보안 탐지(Jailbreak 탐지, Simulator 탐지, Debugging 탐지, Memory Tampered 탐지, Unauthorized Signature 탐지)를 수행합니다.
검사 결과를 전달받으려면 AppSaferDelegate를 설정해야 합니다.
func checkTampering()
- (int)checkTampering
반환 값
반환값 | 설명 |
---|---|
SUCCESS(0) | 검사 시작 성공 |
FAIL(-1) | 검사 시작 실패 |
BLOCK(2) | 보안 정책을 위반하여 차단 |
BEFOREINIT(3) | App Safer가 초기화되지 않음 |
예제
Swift
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()
}
}
}
Objective-C
#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 서버에 전송되는 로그에 사용자 ID를 포함하고자 할 때 설정합니다.
func setUserId(_ userId: String!) -> Int32
- (int)setUserId:(NSString *)userId
매개변수
매개변수 | 설명 |
---|---|
userId | 설정하고자 하는 사용자 식별자 |
반환 값
반환 값 | 설명 |
---|---|
SUCCESS(0) | 설정 성공 |
FAIL(-1) | 설정 실패 |
예제
Swift
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")
}
}
}
Objective-C
#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");
}
}
App Safer iOS 콜백 함수 설명
App Safer의 검사 함수는 모두 비동기로 동작하며, 결과 처리는 AppSaferDelegate를 통해 위임됩니다.
만약 검사 결과를 받고 싶다면 App Safer에서 제공하는 AppSaferDelegate를 구현하고 initAppSafer() 함수를 이용해 등록해야 합니다.
Swift를 사용할 경우 struct
가 아닌 class
에 구현해야 하며 AppSaferDelegate와 NSObject를 모두 추가해야 합니다.
appSaferDidInitFinish
initAppSafer() 함수 호출 후 초기화 완료 시 결과를 전달합니다.
func appSaferDidInitFinish(_ result: Int32)
- (void)appSaferDidInitFinish:(int)result
매개변수
매개변수 | 설명 |
---|---|
SUCCESS(0) | 초기화 성공 |
FAIL(-1) | 초기화 실패 |
BLOCK(2) | 보안 정책 위반으로 차단 됨 |
예제
Swift
func appSaferDidInitFinish(_ result: Int32) {
print("appSaferDidInitFinish result: \(result)");
if(result == BLOCK) {
print("Device is blocked!");
// add to exit application logic
}
}
Objective-C
#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) | 차단 됨 |
예제
Swift
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
}
}
Objective-C
#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() 함수 호출 후 탈옥이 탐지되는 시점에 호출됩니다.
checkTampering() 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용합니다.
func appSaferDetectedJailbreak()
- (void)appSaferDetectedJailbreak
예제
Swift
func appSaferDetectedJailbreak() {
print("[DETECT] appSaferDetectedJailbreak");
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>
@implementation ViewController
- (void)appSaferDetectedJailbreak {
NSLog(@"[DETECT] appSaferDetectedJailbreak");
}
appSaferDetectedSimulator
checkTampering() 함수 호출 후 가상 머신이 탐지되는 시점에 호출됩니다.
checkTampering() 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용합니다.
func appSaferDetectedSimulator()
- (void)appSaferDetectedSimulator
예제
Swift
func appSaferDetectedSimulator() {
print("[DETECT] appSaferDetectedSimulator");
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>
@implementation ViewController
- (void)appSaferDetectedSimulator {
NSLog(@"[DETECT] appSaferDetectedSimulator");
}
appSaferDetectedDebugging
checkTampering() 함수 호출 후 디버깅이 탐지되는 시점에 호출됩니다.
checkTampering() 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용합니다.
func appSaferDetectedDebugging()
- (void)appSaferDetectedDebugging
예제
Swift
func appSaferDetectedDebugging() {
print("[DETECT] appSaferDetectedDebugging");
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>
@implementation ViewController
- (void)appSaferDetectedDebugging {
NSLog(@"[DETECT] appSaferDetectedDebugging");
}
appSaferDetectedMemoryTampered
checkTampering() 함수 호출 후 메모리 변조가 탐지되는 시점에 호출됩니다.
checkTampering() 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용합니다.
func appSaferDetectedMemoryTampered()
- (void)appSaferDetectedMemoryTampered
예제
Swift
func appSaferDetectedMemoryTampered() {
print("[DETECT] appSaferDetectedMemoryTampered");
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>
@implementation ViewController
- (void)appSaferDetectedMemoryTampered {
NSLog(@"[DETECT] appSaferDetectedMemoryTampered");
}
App Safer iOS Use Case
초기화
Swift
import SwiftUI
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()
}
}
}
class AppSaferDelegator: NSObject, AppSaferDelegate {
static let delegator = AppSaferDelegator()
private override init() {}
func appSaferDidInitFinish(_ result: Int32) {
print("appSaferDidInitFinish result \(result)");
if(result == BLOCK) {
print("Device is blocked!");
// add to exit application logic
}
}
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
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
} else if(res == FAIL) {
// init fail
}
} else {
NSLog(@"AppSafer is nil");
}
}
- (void)appSaferDidInitFinish:(NSUInteger)result msg:(NSString *)message {
NSLog(@"appSaferDidInitFinish result %d", result);
if(result == BLOCK) {
NSLog(@"Device is blocked!");
// add to exit application logic
}
}
실시간 보안 탐지
Swift
import SwiftUI
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()
}
}
}
class AppSaferDelegator: NSObject, AppSaferDelegate {
static let delegator = AppSaferDelegator()
private override init() {}
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
}
}
func appSaferDetectedJailbreak() {
print("[DETECT] appSaferDetectedJailbreak");
}
func appSaferDetectedSimulator() {
print("[DETECT] appSaferDetectedSimulator");
}
func appSaferDetectedDebugging() {
print("[DETECT] appSaferDetectedDebugging");
}
func appSaferDetectedMemoryTampered() {
print("[DETECT] appSaferDetectedMemoryTampered");
}
}
Objective-C
@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");
}
}
- (void)appSaferDidCheckTamperingFinish:(int)result {
if(result == BLOCK) {
[self.msgbox setText:@"Device is blocked!"];
// add to exit application
}
NSLog(@"appSaferDidCheckTamperingFinish result %@",
result == FAIL ? @"FAIL" :
result == SAFE ? @"SAFE" :
result == DETECT ? @"DETECT" :
result == BLOCK ? @"BLOCK": @"UNKNOWN");
}
- (void)appSaferDetectedJailbreak {
NSLog(@"[DETECT] appSaferDetectedJailbreak");
}
- (void)appSaferDetectedSimulator {
NSLog(@"[DETECT] appSaferDetectedSimulator");
}
- (void)appSaferDetectedDebugging {
NSLog(@"[DETECT] appSaferDetectedDebugging");
}
- (void)appSaferDetectedMemoryTampered {
NSLog(@"[DETECT] appSaferDetectedMemoryTampered");
}
본 서비스는 글로벌 리전 서비스로도 제공됩니다.