[안드로이드] local.properties에 API Key값 숨기기
728x90
반응형

 

 

 

Copyright : https://webauthn.guide/

 

예를 들어보자. Daum 이미지 검색 API를 안드로이드 내부에서 사용한다면...

 

  1. 카카오 개발 계정이 필요할 것이고
  2. 앱키를 얻기 위해 애플리케이션을 등록하고
  3. 등록된 애플리케이션으로부터 REST API 키를 얻고
  4. "Daum 검색" 개발 가이드에서 이미지 검색 API 정보를 얻으면 된다.

 

 

여기서 3번의 REST API를 안드로이드 코드 내부에 들고 있어야 한다면 어딘가에 저장을 할 것이다. 이 저장하는 과정에서 섬세하게 다루지 않는다면 비밀번호처럼 드러나면 안되는 API Key값을 Github 등에서 누구나 접근가능하게 되버려 곤란한 상황을 겪게될 수 있다. (오우 소름)

 

API 키값이 보인다고? 비밀번호나 마찬가지인 키값이? 이게 머선129 ?!?

 

그렇다면 숨겨야 할 값을 안보이게 하는 방법으로 무엇이 있을까?

 

local.properties에 Key값 숨기기

local.properties를 설명하기 전에 해야 할 일이 있다. ".gitignore" 파일 내에 아래와 같이 작성하여 local.properties가 git에 commit되는 것을 사전에 막는다. 또한 뒤에서 언급할 BuildConfig도 버전관리시 등장하면 안되기에 BuildConfig가 존재하는 "build/" 경로 아래를 gitignore로 체크인을 막는다.

// .gitignore
# Local configuration file (sdk path, etc)
local.properties

# Gradle files
.gradle/
build/

local.properties는 빌드 시스템의 로컬 환경 속성을 구성하기 위해 존재하며 여기에는 "sdk.dir"과 같은 SDK의 경로도 기재되어 있다. 이 뿐만 아니라 빌드시 필요한 상수를 갖고 있을 수도 있다. 필자는 local.properties 내에서 "sdk.dir" 아래에 API Key값을 저장했다.

// local.properties
sdk.dir=Android SDK 경로

kakao_api_key="REST API 키"

 

 

이제 그래들 파일에서 Properties를 선언하고 local.properties에 새로 등록된 Key값을 Load해야 한다. Properties의 개념이 궁금하다면 개발문서를 참고하자. 속성의 집합체 정도로 이해해도 된다. app 경로 아래의 "build.gradle"에서 선언한다.

// build.gradle (app)
plugins {
    // 생략
}

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())

android {
    // 생략

    defaultConfig {
        // 생략
        buildConfigField "String", "KAKAO_API_KEY", properties['kakao_api_key']
    }
}

위 코드에서 buildConfigField가 보인다. 선언된 Properties 내부에는 local.properties에서 저장한 'kakao_api_key'값이 존재한다. 이 값을 빌드 후 생성된 BuildConfig에 저장되면 싱글톤으로 언제 어디서든지 사용이 가능하게 된다. 위와 같이 작성 후 빌드를 하면 기존 BuildConfig에서는 보이지 않는 상수값이 나타난다. 당연히 BuildConfig를 위에서 미리 gitignore로 처리하였기 때문에 상수값 유출을 걱정할 필요는 없다.

 

 

이제 BuildConfig를 살펴보자.

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "what.the.mvvm";
  public static final String BUILD_TYPE = "debug";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
  // Field from default config.
  public static final String KAKAO_API_KEY = "sample12345";
}

물론 "sample12345"라고 적혀 있는 것은 예시이다. 여기에는 local.properties에 저장한 키값이 나타날 것이다. 싱글톤으로 어디서든 쓸 수 있으니 필요한 곳에서 사용한 샘플 코드를 보자.

 

class DataModelImpl(private val service: KakaoSearchService) : DataModel {
    override fun getData(
        query: String,
        sort: KakaoSearchSortEnum,
        page: Int,
        size: Int
    ): Single<ImageSearchResponse> {
        return service.searchImage(
            auth = "KakaoAK ${BuildConfig.KAKAO_API_KEY}",
            query = query,
            sort = sort.sort,
            page = page,
            size = size
        )
    }
}

위 사례처럼 그냥 가져다 쓰면 끝이다. 외부로 노출될 염려를 줄이면서 쉽게 키값을 가져다 쓸 수 있게 되었다.

 

 

 

🤔 만약 다른 PC에서 프로젝트를 git clone해서 쓴다면?

이 경우에 하나만 차이가 난다. 바로 local.properties. 이런 키값은 보안적인 이유로 별도로 관리되어야 한다. 실무에서는 외부에 노출이 되면 안되는 이런 값들을 사내에서만 혹은 관계자만 접근 가능한 문서 파일이나 시스템에 저장하고 있는 경우가 있다. 그런 경우에는 해당 문서에 접근하여 다시 local.properties에 키값을 동일하게 작성해주면 된다. 만약 이런 문서가 없다면 키값이 존재하는 시스템(API 키값의 경우 해당 API를 제공하는 업체의 개발 콘솔 등)에 접근하여 키값을 찾아서 local.properties에 작성해준다. 이 정도면 보안성과 편의성을 어느 정도 잡았다고 봐도 되지 않을까?

 

 

 

😵 Error case 1

error: ';' expected

local.properties는 Properties로 선언되는데 이 Properties 내부에 key, value는 String 타입으로 저장된다.

public synchronized Object setProperty(String key, String value) {
        return put(key, value);
}

local.properties에 등록된 키값이 만약 아래와 같다면 String 타입으로 인지하지 못해 본 에러 케이스가 나타날 수 있다.

// BAD
kakao_api_key=sample12345

// GOOD
kakao_api_key="sample12345"

 

 

 

😵 Error case 2

error: unclosed character literal

Error case 1과 유사한 이유로 나타나는 에러 케이스이다. 반드시 큰 따옴표를 사용해야 한다. 아래 솔루션을 참고하자.

// BAD
kakao_api_key='sample12345'

// GOOD
kakao_api_key="sample12345"

 

 

 

😵 Error case 3

buildConfigField parameter specified as non-null is null

Properties 선언이 잘못되어 있는 경우 위와 같은 Error를 볼 수 있다. "app/build.gradle"에 제대로 작성되어 있는지 확인하자.

// BAD
properties.load 코드가 작성되어 있지 않음

// GOOD
properties.load(project.rootProject.file('local.properties').newDataInputStream())

 

 

 

참고자료
- local.properties이용해서 API KEY 숨기기
- Error in build config in Android Studio
- Insert resValue in gradle file
- Hiding API keys in local.properties

 

 

 

고작 요거 정리하는데 시간이 후딱 지나가네. 이만 자야겠다. 벌써 새벽 5시다.

 

 

 

 

😴

 

 

 

728x90
반응형