본문 바로가기

iOS App SandBox 본문

iOS Technologies

iOS App SandBox

SJ_Repsect 2025. 11. 8. 17:00

왜 Sandbox 라고 부를까?

애플의 경우 기술 개념을 추항화 할때 보통 고유 명사로 설명하는 방식을 선호하는 것 같다.

App SandBox 역시 sandbox (n.) = 모래상자, 모래밭

모래 상자안에서만 놀수 있다는 물리적인 비유로 그 밖의 공간에는 손댈수 없다는 은유적인 표현이다.

앱(macOS, iOS .. 등등)이 시스템 리소스에 제한된 범위 내에서만 작동하여 시스템 훼손을 원천 차단해버린다.

Sandbox 구조

눈으로 보는게 아무래도 더 기억에 남기때문에 직접 파악해보자

아무 앱을 시뮬레이터로 빌드 시켜본 후

시뮬레이터는 Xcode에서 Widnow/Devices and Simulators 에서 Identifier를 확인할 수 있다.

~/Library/Developer/CoreSimulator/Devices/"Identifier"

경로로 들어가보자

해당 경로를 확인해보면 우리의 앱은 /var/mobile/Containers/Data/Application/<UUID>/ 에 생성되어있음을 확인할 수 있다.

iOS 기기는 샌드박스 정책이 완전한 커널 레벨로 적용돼 있기 때문에 Finder나 Xcode로는 내부에 직접 접근할 수 없다.

실제 디바이스로 테스트해볼 경우에는 Download Container를 통해 xcappdata 파일을 다운받을 수 있고, Show Package Contents를 하면 내부 폴더 구조를 볼 수 있다.

디렉토리 용도
documents/ 사용자가 만든 문서나 영구 데이터 저장
Library/ 앱 설정, 캐시 등 내부 관리 데이터
tmp/ 임시 파일 (앱 종료 시 삭제될 수 있음)

실험

실제 Swift로 직접 FileManager 를 통해 저장해보자

let docURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

let fileURL = docURL.appendingPathComponent("sandbox_test.txt")

let text = "Hello Sandbox! 👋"
try? text.write(to: fileURL, atomically: true, encoding: .utf8)

print("파일 저장 완료:", fileURL.path)

Document 경로로 지정했기 때문에 해당 URL에 파일이 저장된 모습

tmp 폴더

temp 폴더에 저장하는 데이터는 필요없다고 판단되면 앱이 실행 중이 아닐 때는 시스템이 이 디렉터리를 삭제할 수 있다.

let tmpURL = FileManager.default.temporaryDirectory
let tmpFile = tmpURL.appendingPathComponent("temp_note.txt")
try? "Temporary".write(to: tmpFile, atomically: true, encoding: .utf8)
print("tmp 파일:", tmpFile.path)

Library 폴더

let libURL = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!
let cacheFile = libURL.appendingPathComponent("cache_info.txt")
try? "Library Test".write(to: cacheFile, atomically: true, encoding: .utf8)
print("Library 파일:", cacheFile.path)

잘 저장된다.

document, library, tmp이 아닌 앱 내부에 저장해보기

func writeContainer() {
        let tmpURL = FileManager.default.temporaryDirectory
        let parentURL = tmpURL.deletingLastPathComponent()
        let fileURL = parentURL.appendingPathComponent("test.txt")

        do {
            try "Hello Sandbox".write(to: fileURL, atomically: true, encoding: .utf8)
            print("Caches 파일 생성 성공:", fileURL.path)
        } catch {
            print("Caches 파일 생성 실패:", error)
}
Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “test.txt” in the folder “2B5745B1-D570-4DB0-99DD-AD5728853EA3”." UserInfo={NSFilePath=/private/var/mobile/Containers/Data/Application/2B5745B1-D570-4DB0-99DD-AD5728853EA3/test.txt, NSURL=file:///private/var/mobile/Containers/Data/Application/2B5745B1-D570-4DB0-99DD-AD5728853EA3/test.txt, NSUnderlyingError=0x1562deaf0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}} }

시뮬레이터의 경우에는 저장이 됌
but 실기기는 권한이 없다고 나옴

다른 앱 디렉토리 접근

let otherAppPath = "/var/mobile/Containers/Data/Application/69614363-0D00-4E00-9151-9FD092B9ADB1/Documents/test.txt"
let url = URL(fileURLWithPath: otherAppPath)

do {
    try "Hello?".write(to: url, atomically: true, encoding: .utf8)
} catch {
    print("❌", error)
}
Error Domain=NSCocoaErrorDomain Code=4 "The folder “test.txt” doesn’t exist." UserInfo={NSUserStringVariant=(
    Folder
), NSFilePath=/var/mobile/Containers/Data/Application/69614363-0D00-4E00-9151-9FD092B9ADB1/Documents/test.txt, NSURL=file:///var/mobile/Containers/Data/Application/69614363-0D00-4E00-9151-9FD092B9ADB1/Documents/test.txt, NSUnderlyingError=0x600000c35860 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

결과는 아예 다른 파일이 있는 줄도 모른다. 마치 Sanbox끼리는 서로 독립적으로 격리되어있는 것 처럼 보인다.

다른 앱 디렉토리 접근 2

만약 App group Entitlement 를 허락한다면 ?

동일한 Team ID라면 공유가능 (같은 팀의 프로비저닝 프로파일로 서명돼야 함)

위젯 같은 경우에 데이터 교환을 위해서 App group을 사용했었는데, 해당 경로는 shared/AppGroup/UUID 에서 확인할 수 있었다.

같은 프로비저닝 파일이라면 둘다 접근가능할 수 있었다.

Application A
└── /var/mobile/Containers/Data/Application/<UUID_A>/

Application B
└── /var/mobile/Containers/Data/Application/<UUID_B>/

공유 폴더(App Group)
└── /var/mobile/Containers/Shared/AppGroup/0D1B1F5D-...
     └── test.txt 

즉 두 앱은 자신만의 샌드박스를 만들게 된다.

Comments