노트

모바일 네이티브 저장소

프론트엔드#security · 연결된 개념 6개

쉽게 말하면

네이티브 저장소는 앱 본체가 쓰는 서랍과 금고예요. 설정 같은 건 서랍에, 로그인 비밀 같은 건 금고에 넣어서 앱을 껐다 켜도 남아요. 앱 안 웹 화면의 사물함과는 다른 가구예요.

비유의 한계 서랍은 잠기지 않아요. UserDefaults와 SharedPreferences는 암호화 없이 저장되니 비밀은 금고에 둬요. 다만 Android Keystore는 값이 아니라 암호화 키를 넣는 금고라, 데이터는 그 키로 암호화해 따로 저장해요.

모바일 앱이 네이티브 코드로 데이터를 저장해, 앱을 다시 실행해도 남게 하는 저장소를 통틀어 부른다. iOS와 Android에 통일된 저장소 하나가 있는 것이 아니라, 데이터 종류에 따라 플랫폼 API를 고른다.

용도iOSAndroid
작은 설정값UserDefaultsJetpack DataStore(예전엔 SharedPreferences)
구조화된 데이터Core DataRoom(SQLite)
파일앱 샌드박스앱 전용 저장소(app-specific storage)
비밀 값·키KeychainAndroid Keystore(키)

설정 저장소는 잠겨 있지 않다

  • Apple 문서에 따르면 UserDefaults는 디스크에 암호화 없이 저장한다. 개인 정보나 민감한 정보는 넣지 말고 Keychain에 두라고 한다
  • Android는 키-값 데이터에 SharedPreferences 대신 DataStore를 권한다. DataStore는 코루틴과 Flow로 비동기·트랜잭션 방식으로 저장한다. 작은 데이터용이라 큰 데이터나 관계가 있는 데이터는 Room을 쓴다
  • OWASP(Open Worldwide Application Security Project)도 Android에서 민감한 데이터를 SharedPreferences에 두지 말라고 한다
  • Android에서는 앱을 지우면 앱 전용 파일, preferences, Room DB가 함께 지워진다

비밀 값: Keychain과 Keystore는 성격이 다르다

  • iOS Keychain은 비밀번호·토큰 같은 작은 비밀 데이터를 암호화된 데이터베이스에 저장한다. 값 자체를 넣는다
  • Android Keystore는 암호화 키를 기기 밖으로 꺼내기 어렵게 보관한다. 키 자료는 앱 프로세스에 들어오지 않고, 암호화·서명은 시스템 프로세스가 대신한다. 기기가 지원하면 키를 TEE(Trusted Execution Environment)나 StrongBox 같은 보안 하드웨어에 묶고, 사용자가 잠금 화면 인증이나 생체 인증을 해야만 키를 쓰게 할 수도 있다. 토큰을 지키려면 Keystore 키로 암호화한 뒤 암호문을 앱 저장소에 둔다
  • 이 패턴을 감싸던 Jetpack security-crypto(EncryptedSharedPreferences)는 2025년에 모든 API가 폐기(deprecated)됐다. 플랫폼 API와 Keystore를 직접 쓰라는 안내다

보안 저장소를 써도 클라이언트를 믿을 수는 없다. OWASP는 클라이언트 쪽 통제는 모두 우회될 수 있다고 보고 서버에서도 검사하라고 한다. 자격 증명을 앱에 하드코딩하지 말고, 사용자 비밀번호는 기기에 저장하지 말고, 취소할 수 있는 토큰을 쓰라고 권한다.

웹뷰 저장소와는 별개다

앱 안 웹뷰의 웹 페이지는 localStorage·sessionStorage나 쿠키 같은 웹 저장소를 쓴다. 이것은 출처별로 나뉜 웹뷰의 데이터이고, 네이티브 저장소와 자동으로 공유되지 않는다. 네이티브에 둔 값을 웹이 써야 하면 브리지로 명시적으로 넘긴다.

  • Android WebView는 DOM 저장소 API가 기본으로 꺼져 있다. WebSettings.setDomStorageEnabled(true)를 켜야 localStorage를 쓸 수 있다
  • iOS WKWebView는 기본 데이터 저장소(WKWebsiteDataStore.default())가 웹사이트 데이터를 디스크에 남긴다. nonPersistent()로 만든 저장소는 데이터를 메모리에만 두고 디스크에 쓰지 않는다(비공개 브라우징용)

긴 수명의 인증 정보를 웹뷰의 localStorage나 JS 변수에 두면 XSS(Cross-Site Scripting)가 생겼을 때 주입된 스크립트가 바로 읽어 갈 수 있다. 네이티브가 인증을 맡고 토큰은 보안 저장소에 둔다. 웹뷰에는 꼭 필요한 값만 브리지로 넘기거나, 서버가 발급한 짧은 세션을 HttpOnly 쿠키로 설정한다(HTTP 쿠키, 세션 인증). 토큰 형식은 JWT를 본다.

출처: Apple — UserDefaults · Apple — Core Data · Apple — Keychain services · Apple — WKWebsiteDataStore · Android — Data and file storage overview · Android — DataStore · Android — Android Keystore system: Security features · Android — Security library release notes · Android — WebSettings · OWASP — Mobile Application Security Cheat Sheet

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 저장소 역할 분담 (DB·캐시·큐·검색)

    서버 애플리케이션 옆에는 거의 늘 관계형 DB, 인메모리 캐시, 메시지 브로커(message broker), 검색 엔진이 붙는다. 하나로 다 하지 않는 이유는 데이터의 성격(영구성·속도·전달·검색)마다 잘하는 도구가 다르기 때문이다.

  • 무상태와 상태 유지

    무상태(stateless)는 서버가 이전 요청을 기억하지 않아도 요청 하나만 보고 처리할 수 있는 구조이고, 상태 유지(stateful)는 서버가 요청 사이에 클라이언트 상태를 저장해 두고 다음 요청을 처리할 때 그 상태를 찾아보는 구조다.

  • 권한 있는 데이터(기준 데이터)

    권한 있는 데이터(authoritative data)는 어떤 값이 맞는지 판단할 때 최종 기준으로 삼기로 정한 데이터의 원천이다. 여러 곳에 같은 정보가 있고 값이 서로 다르면 권한 있는 쪽을 따르고, 나머지는 사본으로 다룬다. 데이터 관리에서는 이런 저장 시스템을 기록 시스템(System of Record, SoR)이라 부른다.

  • 비밀번호 저장: 인코딩·암호화·해싱

    비밀번호는 원문으로 저장하지 않고, 느린 단방향 해시(one-way hash)로 바꿔 저장한다. 로그인할 때는 입력값을 같은 방식으로 해시해 저장된 값과 비교한다. 인코딩·암호화·해싱은 비슷해 보이지만 목적이 다르다.

  • Redis (인메모리 저장소)

    Redis는 데이터를 메모리에 두는 키-값 저장소(key-value store)다. 디스크 기반 DB보다 훨씬 빠르지만, 기본적으로 휘발성에 가깝게 다루는 것이 안전하다. 문자열뿐 아니라 리스트·해시·셋·정렬된 셋 같은 자료구조를 명령 하나로 다룬다.

보기 옵션