Flutter에서 API Key를 숨기는 방법 (feat.GoogleMap)

eora21·2024년 1월 27일
0

GoogleMap API Key를 노출하기 싫어 개인적으로 .env를 적용한 일지입니다. 다만 구글맵은 API 설정에서 어플을 제한하는 방법을 사용하여 키가 노출되어도 함부로 사용할 수 없게끔 합니다. 즉 GoogleMap은 .env를 적용할 필요가 없으며, 해당 블로그 글을 참조하여 세팅하시면 되겠습니다.

외부 Key가 필요한 패키지를 Flutter에서 사용하려면 안드로이드, iOS 설정에 패키지 API 키를 설정해야 합니다.
그러나 해당 설정이 git에 올라간다면 API key가 그대로 노출되게 됩니다.
이를 방지하기 위해서는 환경변수 .env를 적용해서 각각의 세팅 파일이 직접적인 key가 아닌 환경변수를 참조하도록 해야 합니다.

Key를 완벽하게 보호하고 싶어요

key를 .env를 통해 설정하여 git에 노출되는 것을 막았음에도 불구하고, 배포된 App을 사용자가 (리버스 엔지니어링 등으로)직접 뜯어본다면 알 수 있다고 합니다.
이를 막기 위해 암호화 및 난독화를 생각했고, 이리저리 알아보았으나..

  1. 매니페스트에 GoogleMap API Key를 암호화, 난독화하여 사용하는 방법은 없다.
  2. 따라서 API 키 제한 설정을 통해 지정된 앱만 사용할 수 있도록 해야 한다.
  3. 다만 구글맵이 아닌 다른 API Key같은 경우 노출을 최소화하기 위해 .env 파일을 이용하여야 한다.

..라는 결론을 얻게 되었습니다. 따라서 이번 글에는 .env 이용, API 키 제한 설정에 대해 작성하겠습니다. 덧붙여 난독화를 적용하려면 어떠한 방법을 사용하는 지도 알아보겠습니다.

.env 사용법

.env

프로젝트 루트 디렉터리에 .env 파일을 생성하고 원하는 key를 적습니다. 구글맵을 예시로 적어보도록 하겠습니다.

GOOGLE_MAPS_API_KEY=발급받은 키

그 후 .gitignore.env*를 적어줍시다(이미 적혀져 있을 수도 있습니다).

flutter_config

환경 변수 사용을 위해 해당 패키지를 적용합니다.

설치

flutter pub add flutter_config

혹은 직접 pubspec.yaml 파일에

dependencies:
  ...
  flutter_config: ^2.0.2

를 작성하시면 됩니다.

main 변경

.env를 사용하기 위해선 main.dart의 main()을 변경해줘야 합니다..만 저는 해당 설정을 하지 않아도 잘 돌아가더라구요. 우선 설정 없이 해보시고, 만약 동작하지 않는다면

import 'package:flutter_config/flutter_config.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized(); // Required by FlutterConfig
  await FlutterConfig.loadEnvVariables();

  runApp(MyApp());
}

이렇게 작성해 주세요.

안드로이드에 키를 세팅해야 하는 경우

android/app/build.gradle

apply from: project(':flutter_config').projectDir.getPath() + "/dotenv.gradle"을 맨 밑에 추가합니다(빌드 시 Reading env from: .env를 띄우기 위함입니다).

android/app/src/main/AndroidManifest.xml

application 안에

<meta-data
           android:name="com.google.android.geo.API_KEY"
           android:value="@string/GOOGLE_MAPS_API_KEY" />

를 작성해 주세요.
구글맵은 위와 같으나, 다른 API의 경우는 공식문서를 참조하셔서 올바르게 적어주세요.

iOS 세팅

ios/Runner/AppDelegate.swift

...
import GoogleMaps  // 추가
import flutter_config  // 추가

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
  	...
  ) -> Bool {
 	GMSServices.provideAPIKey(FlutterConfigPlugin.env(for: "GOOGLE_MAPS_API_KEY"))  // 추가
    ...
  }
}

이렇게 작성해주시면 됩니다.
이 또한 마찬가지로, 구글맵이 아닌 다른 API의 경우 공식문서를 참조하셔서 적어주시면 됩니다.

만약 난독화를 사용하려면?

envied

환경 변수를 작성하는 패키지로 envied를 사용하겠습니다.

설치

flutter pub add envied
flutter pub add --dev envied_generator
flutter pub add --dev build_runner

혹은 직접 pubspec.yaml 파일에

dependencies:
  ...
  envied: ^0.5.3
  
dev_dependencies:
  ...
  build_runner: ^2.4.8
  envied_generator: ^0.5.3

작성하시면 됩니다.

.env

프로젝트 루트 디렉터리에 .env 파일을 생성하고 원하는 key를 적습니다.

API_KEY=발급받은 키

env.dart

해당 키를 사용할 env.dart 파일을 생성합니다. 저는 lib/env/env.dart에 생성하였습니다.

import 'package:envied/envied.dart';

part 'env.g.dart';

(path: '.env')
abstract class Env {
  (varName: 'API_KEY', obfuscate: true)
  final String apiKey = _Env.apiKey;
}

현재는 env.g.dart 파일이 없기 때문에 빨간 줄이 그어져 있을 것입니다. 해당 파일을 생성하기 전 .gitignore에 파일들이 올라가지 않도록 합시다.

.gitignore

앞서 작성한 .env 파일과 env.g.dart 파일이 올라가지 않도록 해야 합니다.

.env*
lib/env/env.g.dart

.env*는 자동으로 작성이 되어 있을 수 있습니다.

env.g.dart 생성

env.g.dart는 직접 생성하지 않고 build_runner에게 맡기도록 하겠습니다.
Flutter 루트 디렉터리에서 터미널을 열고

flutter pub run build_runner build — delete-conflicting-outputs

를 실행한 후 env.g.dart 파일이 생성되었는지 확인합시다.

파일이 생성되었다면 envied 문서를 참고하셔서 사용하시면 되겠습니다.

profile
나누며 타오르는 프로그래머, 타프입니다.

0개의 댓글