Flutter에서 환경변수 설정하기

Seong-Am Kim
5 min readMar 3, 2024

--

Photo by Franck on Unsplash

Flutter 개발을 하면서 개인적으로 가졌던 고민이 환경변수를 어떻게 하면 보안적으로 안전하게 지킬 수 있을까 하는 고민이였다.

해당 부분에 대해 나름 도출한 결과를 정리해보려고 한다.

흔히 환경변수를 쓴다고 하면 .env 파일을 생성하고 flutter_dotenv 패키지를 이용해 사용 하는것이 가장 손쉽게 접근할 수 있는 방법 중 하나라고 생각한다.

웹에서는 아주 흔한 방식으로 나도 처음엔 해당 방법을 사용해서 앱을 구현했다.

하지만 우연히 아래글을 보게 되었다.

why not to use dotenv on flutter

요약 하자면 assets 으로 들어간 파일에 대해선 이를 apk 파일로 만들었을때 적은 노력으로 .env 에 내용에 대해 볼 수 있다.

해당 이슈에 대해서 flutter_dotenv 의 메인테이너에게 문제를 제기했고 답변을 얻었다.

https://github.com/java-james/flutter_dotenv/issues/73

결론적으론 .env 는 누구나 확인할 수 있으므로 보안적으로 민감한 정보를 .env 파일에 저장하지 말라는게 요점이다.

생각해보면 이는 당연한 것으로 모든 프론트와 앱이 해당 되는 이슈기도 하다.

하지만 내가 고민 했던건 해커(공격자)로 하여금 너무나 쉽게 .env 를 읽을 수 있다는게 문제였다.

흔히 이를 방지 하기 위해 난독화 작업을 진행하게 되는데 assets이 되면 정적 리소스로 분류가되어 난독화가 되지 않는다.

그럼 우리에게는 어떤 선택지가 있을까?

  1. 환경변수가 들어간 dart 파일을 만들어 사용한다.
  2. — dart-define 옵션을 사용 한다.

우선 첫번째 1번의 경우 말그대로 하드코딩으로 dart 파일을 만들어서 사용한데 사실 해당 부분은 난독화는 가능하겠지만 환경변수를 사용하는 이유가 보통 버전 관리에서 손쉽게 제외하거나 관리의 편의성을 위함인데 크게 메리트가 느껴지지 않는 부분이다.

하지만 택할 수 있는 방법 중 하나라고 생각한다.

2번째는 dart에서 공식적으로 지원하는 방법으로 컴파일 타임일때 환경변수를 사용가능하게 한다. 예를들어 아래와 같이 실행이 가능하다.

flutter run --dart-define API_KEY=super_secret

하지만 매번 명령행에 적어주는게 상당히 비효율적이다.

이를 보완하기 위해 .env 를 직접 만들어 사용이 가능하다.

API_KEY=super_secret

위의 같이 .env 파일을 만든 후 아래 명령어로 실행가능하다.

flutter run --dart-define-from-file="./.env"

명령어를 매번 입력하기 힘들다면 아래와 같이 VSCode에 .vscode/launch.json파일을 생성하여 디버깅 실행 시 인자를 추가할 수 있다. ( Android Studio 에서의 실행 역시 인자 추가가 가능 하다)

{
"version": "0.2.0",
"configurations": [
{
"name": "flutter_sample",
"request": "launch",
"type": "dart",
"toolArgs": [
"--dart-define-from-file",
"./.env"
]
}
]
}

— dart-define-from-file 이 개인적으로 마음에 들었던 부분은 다트 코드에서 뿐만이 아니라 네이티브인 안드로이드, IOS 모두에서 하나의 환경변수로 사용가능 하다는 점인데 안타깝게도 리서치를 통해서 찾아본 결과 의도한 동작이 아니였고 Flutter 팀이 해당 기능을 버그로 분류한듯 하다.

이슈에도 누군가 코멘트를 남겼듯이 하나의 환경변수로 네이티브의 환경변수까지 설정할 수 가 있어 매우 간편했는데 이에 대한 대안이 현재 딱히 보이지 않아 개인적으로도 아쉬운 상황이다.

— dart-define-from-file을 통해 네이티브 코드의 환경변수를 설정하는 방법은 현재 최신인 3.19.2 버전을 기준으로 정상적으로 아직까지 작동함을 확인했다.

하지만 언제 제거 될지 모르기에 앞으로 개인적으로 앞으로 할 프로젝트에선 사용하지 않기로 결정했다.

혹시나 해당 방법에 대해 궁금하신 분은 아래 블로그 글을 참고하시면 될듯 하다.

(https://medium.com/flutter-community/how-to-setup-dart-define-for-keys-and-secrets-on-android-and-ios-in-flutter-apps-4f28a10c4b6c)

그리고 나머지 선택가능한 방법으론 ENVied 와 같은 코드 제너레이터를 이용하는것인데 개인적으론 개발 할때 코드 제너레이터를 매번 사용 하는게 불호라서 해당 부분은 제외했다.

결론을 짓자면 아래와 같이 정리할 수 있을듯 하다.

위의 소개한 모든 사항들은 개인적으론 기본적으로 보안적으로 안전하지 못하다고 생각한다. 어디까지 환경변수의 복호화를 어렵게 하도록 할뿐 불가능하지가 않다.

따라서 어디까지 개인의 판단하에 환경변수를 사용하는 방법을 설정하면 될듯 하다.

보안적으로 정말 중요한 환경 변수라면 앱의 환경변수가 아니라 백앤드 요청을 통해 인증된 요청에 대해서만 키를 획득할 수 있도록 보안적 조취를 취하는게 맞다고 생각한다.

간단하게는 Firebase의 App Check 와 같은 서비스를 이용해서 앱의 허용된 요청만 응답이 가능하도록 구현하는 것도 방법이라 생각한다.

--

--