Flutter 앱 개발: flutter_secure_storage로 민감한 정보 저장하기

Flutter 앱 개발을 하면서, 사용자 인증 정보나 토큰과 같은 민감한 데이터를 안전하게 저장하려면 보안이 중요한 요소로 작용합니다. 이를 위해 많은 개발자들이 flutter_secure_storage 패키지를 활용합니다.
이 글에서 flutter_secure_storage 패키지가 무엇이고 어떻게 쓰는지 정리해봤습니다.

flutter_secure_storage 사용하기

flutter_secure_storage 란?

flutter_secure_storage는 Flutter 애플리케이션에서 민감한 데이터를 안전하게 저장할 수 있도록 설계된 패키지입니다. 이 패키지는 다음과 같은 기능을 제공합니다:

  • iOS: 키체인(Keychain)을 활용하여 데이터를 암호화 및 저장
  • Android: Keystore를 이용해 암호화된 데이터 저장
  • Web: LocalStorage나 IndexedDB를 활용한 데이터 저장

이 패키지는 플랫폼별 보안 메커니즘을 활용하여 데이터 보안을 강화하며, 특히 인증 토큰, API 키, 비밀번호 등 민감한 데이터를 다룰 때 유용합니다.

Flutter 앱 개발 시 flutter_secure_storage 패키지를 사용하는 이유?

flutter_secure_storage를 사용하는 몇 가지 주요 이유입니다:

  1. 보안성:
    단순한 SharedPreferences나 일반 로컬 스토리지가 아닌, 각 플랫폼의 고유 보안 API를 활용하여 데이터를 암호화합니다.
  2. 사용 편의성:
    데이터 저장 및 읽기 작업이 간단한 API 호출로 이루어져, 개발 생산성을 높일 수 있습니다.
  3. 플랫폼 독립성:
    Flutter 앱의 핵심 철학에 맞춰 다양한 플랫폼에서 일관된 방식으로 데이터를 다룰 수 있습니다.
  4. 개발자 커뮤니티와 문서 지원:
    인기 패키지 중 하나로, 문제가 발생했을 때 관련 자료를 찾기 쉽습니다.

flutter_secure_storage의 장단점

장점:

  • 보안성: 암호화를 기본으로 지원하여 민감한 데이터 보호에 적합
  • 다중 플랫폼 지원: iOS, Android, Web 환경에서 모두 사용 가능
  • 사용의 간편함: 초기 설정이 간단하고 코드 작성이 직관적

단점:

  • 웹 환경 보안: Web에서 사용하는 LocalStorage는 플랫폼에 따라 완전한 보안이 보장되지 않을 수 있음
  • 플랫폼 의존적 문제: 플랫폼별 보안 메커니즘 차이로 인해 예상치 못한 동작이 발생할 수 있음
  • 디버깅 제한: 암호화된 데이터를 직접 확인하기 어려움

 

그렇다면 flutter_secure_storage에 저장된 값은 어떻게 확인할 수 있을까요?

flutter_secure_storage에 저장된 값을 보는 디버깅 방법

Flutter 앱에서 암호화된 데이터를 디버깅하려면, 데이터 저장 및 호출 과정을 추적하는 몇 가지 방법을 사용할 수 있습니다:

  1. 디버깅 로그 사용:
    데이터를 저장하거나 읽기 전에 암호화되기 전의 데이터를 로그로 출력해 확인합니다. 
  2. 플랫폼별 도구 활용:
    • iOS: Xcode의 Keychain Access를 사용해 키체인 데이터를 확인
    • Android: Android Studio에서 Device File Explorer를 사용해 Keystore 파일 조회
  3. 임시 해제:
    개발 단계에서만 데이터를 암호화하지 않고 저장하여 내용을 쉽게 확인.
    (주의: 반드시 개발 모드에서만 사용해야 하며, 프로덕션에서 금지)

flutter_secure_storage 사용 방법

1. 패키지 설치

flutter_secure_storage를 사용하려면 먼저 패키지를 프로젝트에 추가해야 합니다.
참고 링크

  1. pubspec.yaml에 추가
    dependencies: flutter_secure_storage: ^9.2.2
  2. flutter pub get 패키지 설치

2. 기본 사용법

  1. flutter_secure_storage 가져오기
    import 'package:flutter_secure_storage/flutter_secure_storage.dart';'
    
  2. 인스턴스 생성: 인스턴스를 생성하여 데이터를 저장하거나 읽을 수 있습니다.
    final storage = FlutterSecureStorage();
  3. 데이터 저장: 키-값 쌍으로 데이터를 저장합니다.
    await storage.write(key: 'authToken', value: 'your_secure_token');
  4. 데이터 읽기 저장된 데이터를 읽습니다. 키에 해당하는 값이 없으면 null을 반환합니다.
    String? token = await storage.read(key: 'authToken');
    print('Token: $token');
    
  5. 모든 데이터 읽기 저장된 모든 데이터를 Map 형태로 읽어옵니다.
    Map<String, String> allData = await storage.readAll();
    print('All Data: $allData');
    
  6. 데이터 삭제 특정 키에 해당하는 데이터를 삭제하거나 전체 데이터를 삭제할 수 있습니다.
    // 특정 키 삭제
    await storage.delete(key: 'authToken');
    
    // 전체 데이터 삭제
    await storage.deleteAll();
    
  7. 키 존재 여부 확인 데이터가 존재하는지 확인합니다.
    bool exists = await storage.containsKey(key: 'authToken');
    print('Exists: $exists');

Platform Exception...The specified item already exists in the keychain.. 에러

Unhandled Exception: PlatformException(Unexpected security result code, Code: -25299, Message: The specified item already exists in the keychain., -25299, null) 에러 발생

저는 어떤 값이 변할때 기존에 storage에 저장된 값에 새로 업데이트 되기를 원했습니다.

그런데 아래와 같은 에러가 발생하면서 storage에 새로운 값 저장이 잘 되지 않는 버그가 생겼습니다.

Unhandled Exception: PlatformException(Unexpected security result code, Code: -25299, Message: The specified item already exists in the keychain., -25299, null)

 

에러 해결

아래와 같이 기존 데이터를 지우고 새로 저장하는 방식으로 해결했습니다.

await storage.delete(key: 'key');
await storage.write(key:key, value: value);

추가 설정

// AS-IS
  final storage = FlutterSecureStorage();
// TO-BE
  final storage = FlutterSecureStorage(
    iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
    aOptions: AndroidOptions(encryptedSharedPreferences: true),
  );

iOptions, aOptions는 각각 ios와 android 플랫폼에서 데이터를 안전하게 저장하기 위해 사용되는 설정입니다.

iOS: Keychain에 데이터를 저장하며, 기기가 처음으로 잠금 해제된 이후에는 데이터를 사용할 수 있습니다.

Android: EncryptedSharedPreferences를 사용해 데이터를 암호화한 상태로 저장합니다.

  • iOptions – accessibility 옵션: Keychain 데이터에 접근할 수 있는 시점을 지정합니다.
    • KeychainAccessibility.first_unlock:
      • 기기가 재부팅된 후 최초로 잠금이 해제되었을 때 Keychain 데이터에 접근이 가능합니다.
      • 보안과 편의성 간의 균형을 맞춘 옵션입니다.
      • 앱이 백그라운드에서 실행 중인 경우에도 Keychain에 접근 가능.
    • KeychainAccessibility.unlocked:
      • 기기가 현재 잠금 해제된 상태에서만 Keychain 데이터에 접근할 수 있습니다.
      • 보안이 가장 높은 설정 중 하나이며, 앱이 백그라운드에서 실행 중인 경우에는 접근할 수 없습니다.
    • KeychainAccessibility.always:
      • 기기가 잠겨 있어도 언제나 Keychain 데이터에 접근할 수 있습니다.
      • 편의성은 높지만 보안 수준이 낮습니다.
      • 민감한 데이터를 저장하기에는 적합하지 않습니다.
    • aOptions – encryptedSharedPreferences
      • true: 데이터를 Android EncryptedSharedPreferences에 저장합니다.
        • 이 설정은 Android 6.0 (API 23) 이상에서 지원되며, 데이터는 암호화되어 저장됩니다.
        • EncryptedSharedPreferences는 앱에 대해 강력한 보안을 제공합니다.
        • 기본적으로 AES-256 암호화를 사용합니다.
      • false: 데이터를 일반 SharedPreferences에 저장합니다.
        • 이 경우 데이터는 암호화 되지 않습니다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Scroll to Top