티스토리 뷰
개인 프로젝트에서 사용자가 찍은 사진을 기기 로컬에 저장하는 기능을 구현했다. 서버가 존재하지 않기 때문에 서버에 사진이 올라갔을때의 보안 걱정은 따로 하지 않았고, iOS는 워낙 보안이 좋으니 따로 신경 쓸 부분은 없다고 생각했다.
프로젝트에는 앱 안에서 발생하는 사용자 이벤트를 모니터링하기 위해 Firebase Analytics와 Crashlytics를 붙여두었다. 근데 이 SDK들이 내 앱과 같은 프로세스 안에서, 같은 권한으로 실행된다면 로컬에 저장된 사진은 정말 안전한 걸까? 라는 의문이 들었다.
iOS의 보안을 이야기할 때 빠지지 않는 것이 샌드박스인데, 막상 샌드박스가 어떤 경계를 만들고 어디까지 보호해주는지는 정확히 모르다보니 이번 포스팅에서는 App Sandbox의 구조와 동작 방식을 정리해보고자 한다.
(제가 공부하기 위해 작성한 것이므로 틀린 정보가 있다면 알려주세요!)
📚 App Sandbox
앱이 다른 앱의 데이터나 시스템 영역에 접근하지 못하게 OS 가 강제하도록 한다.

공식 문서를 보면 macOS 앱에서 앱 샌드박스는 앱 권한을 통해 요청된 리소스에만 접근할 수 있도록 제한함으로써 시스템 리소스와 사용자 데이터를 보호한다고 되어 있다.
🤔 그럼 macOS에서만 가능하고 iOS나 ipadOS에서는 앱 샌드박스가 없는건가?
: macOS 에서만 개발자가 켜고 끄는 기능을 선택할 수 있기 때문에 공식 문서에서는 macOS 기준으로 나와있는 거 같다.
macOS 앱을 배포하기 위해서는 app sandbox 기능을 무조건 활성화해야 한다고 한다.
반면 Apple Platform Security 문서에 의하면 iOS/iPadOS/visionOS에서는 모든 서드파티 앱에 자동으로 강제 적용되도록 하며 끄는 옵션 자체가 없다고 한다.
따라서 샌드박스는 모든 apple 플랫폼에서 제공되지만, iOS 계열에서는 모든 서드파티 앱에 기본으로 강제되고 macOS에서는 개발자가 선택해서 적용하는 방식이다.
✏️ 왜 쓰는걸까?

기본적으로 iOS앱을 만들다보면 사용자 데이터를 로컬에 저장하거나 캐시로 활용하는 일이 많다. 만약 모든 앱이 디스크 전체에 자유롭게 접근할 수 있다면 악성 코드에 노출되어 해당 사용자의 모든 데이터를 읽거나 변조하고 시스템 파일까지 건드릴 수 있다.
그래서 샌드박스는 앱마다 자신만의 구역을 만들어서 이 구역 밖의 다른 앱 데이터나 시스템 리소스에는 접근하지 못하도록 막는다. 예를 들어 당근마켓은 카카오톡이 저장한 데이터를 읽을 수 없고 내 앱이 컨테이너에 저장한 사진도 다른 앱에서는 볼 수 없다.
즉 개인프로젝트에서 진행하고 있는 사진앱에서 사진 저장이 앱 컨테이너에 저장된다면 같은 원리로 다른 앱은 접근할 수 없다. 반면 사진을 사진 앱 (Photos 라이브러리)에 저장한다면 얘기가 달라진다. 이건 샌드박스가 아니라 권한 영역이기 때문에 다른 앱에서도 접근할 수 있게 되는데 이는 해당 포스팅과는 다른 주제여서 이쯤 설명하고 넘어가겠다!
샌드박스화된 앱은 자신만의 구역이 생길 뿐 아니라 구역 밖의 사용자가 데이터와 시스템 리소스에 접근할 때도 제한을 받게 된다.
사진에서도 보면 샌드박스가 없을때는 앱의 모든 사용자 데이터와 시스템 리소스에 제한 없이 접근한다. 하드 디스크 그림을 보면 앱이 사용하는 영역(빨간색)이 디스크 전체에 흩어져 있다. 앱이 정상일 때는 문제가 없지만, 장악당하는 순간 공격자도 디스크 전체를 건드릴 수 있게 된다.
반면 샌드박스가 있을때는 앱은 자기 샌드박스 안에서만 제한 없이 접근하고 다른 사용자 데이터와 시스템 리소스에는 기본적으로 접근할 수 없다. 디스크 그림에서도 앱의 영역이 노란 박스 안에 모여있는걸 확인할 수 있다. 즉 앱이 장악당해도 피해 범위가 노란 박스 안으로 한정되기 때문에 비교적 안전하다.
iOS에서 보안이 강하다는 이야기가 여기서 나오게 되었다.
✏️ 샌드박스의 구조

공식 가이드에서는 App Sandbox를 구성하는 요소를 컨테이너 디렉터리, entitlement, 사용자 권한, 권한 분리, 커널 강제 5가지로 정리하고 있다. 이중 iOS 개발자가 체감하는 건 컨테이너 구조여서 이걸 중점적으로 파악해보고자 한다.
iOS 앱이 설치되면 샌드박스 디렉터리 안에 여러 컨테이너가 만들어진다.
- Bundle Container: 앱 번들(.app) 자체이며 쓰기권한이 없다. 설치 시점에 서명되어 변조를 막고 실행중에는 읽기 전용으로 유지된다
- Data Container: 앱과 사용자 데이터를 저장하는 곳이며 아래 네가지를 포함한다.
- Documents/: 사용자가 생성한 콘텐츠를 저장하는 데 사용된다. 이 디렉터리의 내용은 파일 공유를 통해 사용자에게 공개될 수 있으므로 사용자에게 공개할 의향이 있는 파일만 포함해야 한다. 이 디렉터리의 내용은 iTunes와 iCloud에 백업된다.
- Documents/Inbox: 외부 기관에서 앱에 열도록 요청한 파일에 접근하는데 사용된다. 예를 들어 메일 프로그램은 앱과 관련된 이메일 첨부 파일을 해당 디렉터리에 저장한다. 해당 디렉터리에서 앱은 파일을 읽고 삭제할 수 있지만 새 파일을 생성하거나 기존 파일에 쓸 수는 없다. 해당 내용은 iTunes와 iCloud에 백업된다.
- Library: 사용자 데이터 파일을 제외한 모든 파일을 저장하는 최상위 디렉토리이다. 보통 캐시 등이 저장되는 장소이며 해당 디렉토리의 내용은 iTunes와 iCloud에 백업된다.
- Tmp: 앱 실행간에 유지될 필요가 없는 임시 파일을 저장하는데 사용된다. 앱에서는 더 이상 필요하지 않은 파일을 이 디렉터리에서 삭제해야 하며 해당 내용은 iTunes나 iCloud에 백업되지 않는다.
- 추가 Container: iCloud 컨테이너나 App Group 컨테이너처럼 런타임에 권한을 받아 접근하는 공간이다.
즉, 앱은 설치 시점에 각자의 샌드박스 디렉터리를 할당받는데 이 디렉터리가 각 앱의 홈 디렉터리이며 보안을 위해서는 앱이 파일 시스템과 상호작용 할 수 있는 범위는 이 샌드박스 디렉터리 안으로 제한된다.
📍동작방식
1. 앱을 설치하면 OS가 앱 전용 컨테이너를 만든다. 앱은 이 안에서 제한없이 읽고 쓸 수 있다.
2. 앱이 컨테이너 밖의 리소스에 접근하려고 하면 커널이 이 요청을 가로채서 앱에 허용된 범위인지 검사한다. 이 검사는 커널 수준에서 강제되기 때문에 앱 코드로 우회할 수 없다.
3. 허용 범위는 앱의 코드 서명에 포함된 entitlement로 정해진다. 서명에 들어 있기 때문에 앱이 실행 중에 스스로 권한을 늘릴 수 없다.
4. 카메라, 사진, 위치처럼 민감한 리소스는 entitlement가 있어도 끝이 아니라 사용자가 직접 허용해야 접근할 수 있다. 다른 앱의 정보가 필요할 때도 파일을 직접 여는 게 아니라 OS가 제공하는 프레임워크를 거쳐야 한다.
✏️ 한계 및 원칙
그럼에도 불구하고 샌드박스가 완벽하게 보호해주지는 못한다. 샌드박스의 경계는 앱 단위이다. 샌드박스가 앱과 앱이 링크한 프레임워크까지 함께 가둔다고 설명되어 있지만 이 말은 즉 Firebase같은 SDK도 내 앱과 같은 구역 안에서 같은 권한을 가진다는 뜻이다.
SDK가 다른 앱의 데이터로 나가는 건 막아주지만, 내 앱 컨테이너 안의 데이터 SDK가 접근하는 것까지는 막지 않는다.
그래서 샌드박스는 공격을 막는 마지막 방어선이고 개발자는 필요한 권한만 요청하고 민감한 데이터를 어디에 어떤 방식으로 저장할지 전략을 세우는 것이 중요하다.
샌드박스 밖의 리소스를 쓰려면 의도를 명시적으로 밝혀야 한다. macOS에서는 아래 항목을 entitlement로 선언한다.
- Hardware: 카메라, 마이크, USB, 프린터, 블루투스
- Network: 수신/발신 연결
- App Data: 연락처, 위치, 캘린더
- User Files: 다운로드, 사진, 사용자가 선태한 파일 등
반면 iOS에서는 이런 샌드박스 체크박스가 따로 있는 것이 아니라 info.plist에서 Usage Description을 적고 사용자 허용을 받는 방식으로 동작한다.

info.plist를 명시하는건 사용자 동의를 구하는 것이고, entitlement는 샌드박스 계층이다. iOS에서는 앞에 것만 명시하면 됐지만 macOS에서는 두가지 모두를 명시해야 한다.
🤔 마무리
앱 개발을 할 때 로컬에 저장하거나 캐시를 하는 부분에 있어서 iOS는 보안이 좋으니까~ 하고 넘어갔던게 많았는데 샌드박스가 어디까지 보호해주는지 동작과정이나 구조를 알고 나니까 오히려 신경써야 하는 부분이 명확해졌다.
샌드박스가 모든걸 지켜주는 게 기술이 아니라 앱이 뚫렸을때 피해가 번지지 않도록 하는 기술임을 알게 되었다. 샌드박스는 SDK가 다른 앱으로 나가는 것은 막아주지만 내 앱 안의 데이터에 접근하는 것까지는 막아주지 않기 때문에 앱에 어떤 SDK를 넣을지 사용자 데이터를 어디에 어떤 방향으로 저장할지는 온전히 개발자가 판단해야 하는 영역임을 알게 되었다.
다음 포스팅에서는 앱에 포함된 SDK가 어떤 데이터를 수집하는지 선언하게 하는 Privacy Manifest와 기기에 저장된 파일을 암호화하는 Data Protection에 대해서 한번 알아보고자 한다!
참고
https://developer.apple.com/documentation/security/app-sandbox
https://support.apple.com/en-mk/guide/security/sec15bfe098e/web
https://developer.apple.com/documentation/xcode/configuring-the-macos-app-sandbox
'iOS > Swift' 카테고리의 다른 글
| [Swift] Privacy Manifest (0) | 2026.09.24 |
|---|---|
| [Swift] Swift Ownership (Copyable, ~Copyable) (0) | 2026.08.05 |
| [Swift] Swift Concurrency(2) - GCD vs Swift Concurrency (1) | 2026.04.22 |
| [Swift] Swift Concurrency(1) - 동시성 (1) | 2026.04.21 |
| [swift] Swift Concurrency - nonisolated (0) | 2025.12.16 |
- Total
- Today
- Yesterday
- 스위프트
- 백준
- AppGroup
- UITest
- UIKit
- Xcode
- swiftUI
- GCD
- macos
- 프로그래머스
- 클로저
- PrivacyManifest
- rxswift
- awakeFromNib
- closure
- Swift Format
- SwiftOwnership
- XCTest
- combine
- App Sandbox
- Task
- copyable
- Fastlane
- 코딩테스트
- CoreData
- Swift Concurrency
- SWIFT
- ObservableObject
- prepareForReuse
- ios
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
