티스토리 뷰

외부 API를 사용하는 경우 일반적으로 Key Hash 값을 통해 사용자를 인증합니다. 여기서 해시란 무엇이고, 안드로이드 개발 시 키 해시를 얻는 방법과 그 활용법에 대해 설명합니다.

#1> Hash Key란?


오픈 API (카카오맵, FCM, Facebook 로그인 등) 를 사용하려면 해시키를 등록해야 하고, Key Hash가 등록된 앱만 SDK를 이용해 API를 호출할 수 있다고 합니다.

카카오 API의 안드로이드 플랫폼 키 해시 입력란 캡쳐.

이 키 해시(Key Hash)가 무엇이길래 등록을 반드시 해야만 사용할 수 있다고 하는걸까요?

 

키 해시는 특정 데이터(data)를 해시 함수(hash function)에 입력한 결과로 받은 리턴값을 말합니다. key hash를 이해하기 위해서는 이를 생성하는 해시 함수에 대해 이해해야 합니다. 같이 살펴볼까요?

 

# 해시 함수의 정의

위키백과에서는 해시함수에 대해 아래와 같이 정의하고 있습니다.

해시 함수(hash function)는 임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는 함수이다. 해시 함수에 의해 얻어지는 값은 해시 값, 해시 코드, 해시 체크섬 또는 간단하게 해시라고 한다.

해시 함수의 특징은 크게 2가지로 정리할 수 있습니다.

  • 데이터의 길이가 랜덤해도 리턴값의 길이는 일정하다.
  • 입력값이 같으면 리턴값도 언제나 동일하다.

뿐만 아니라 함수의 출력 값만 가지고는 입력값을 추론하는 것이 상당히 어렵습니다. 이런 특징으로 인해 암호화된 key 값이라는 개념으로 보안인증에 사용되곤 합니다.

 

해시 알고리즘의 예 / 출처 : 위키백과

# Key Hash의 활용

API Provider(카카오, 구글 등)는 민감한 정보일 수도 있는 앱의 사이닝 키(signing key)값이 아닌 그 값을 해시한(특히 SHA-1 함수를 통해) hash key를 통해 인증된 사용자인지 여부를 판단합니다. 해시를 통한 사용자 인증의 장점은 해시값이 노출되어도 피해가 전혀 없다는 것입니다. 해시값만 가지고는 원본 데이터를 추론할 수 없기 때문입니다. 따라서 hash key가 노출되어도 입력값인 signing key는 안전합니다.

 

그럼 API Provider는 왜 해시가 등록된 앱에 대해서만 API 요청을 허용하는 것일까요? 그 이유는 바로 무분별한 트래픽을 방지하기 위해서입니다. 일반적으로 무료로 공개되어있는 API는 하루 1천 건, 2천 건 등의 요청수 제한을 두고 있습니다. 또한 제한이 있는 무료 사용자와 요청 제한이 없는 유료 사용자를 구분하는 용도로도 쓰일 수 있습니다.

 

# 정리

  • 키 해시는 해시함수의 출력값을 말한다.
  • 해시함수(e.g. SHA1) 는 입력 데이터의 길이와 관계없이 동일한 길이의 출력값을 만든다.
  • 해시함수는 입력값이 같으면 출력값이 늘 동일하다.
  • API 공급업체에서는 사용자 구분을 위해 이 해시함수의 출력값인 Key Hash를 사용한다.

참고로 해시함수는 MD5계열, SHA 계열, CRC32등이 있습니다. 이 쓸모 있어 보이는 키 해시, 어떻게 얻을 수 있을까요?

 

 

#2> Key Hash 획득하기


키 해시를 획득하는 방법에 대해 설명하기에 앞서 원론적인 개념부터 짚고 넘어가겠습니다. Android Application은 Java 기반으로 구현합니다. 이 말인 즉, Android 개발자의 개발 머신에는 JDK가 설치되어 있다는 뜻입니다. 또한, jdk\bin 폴더에는 다양한 어플리케이션이 존재하는데, 이 중 해시키를 생성할 수 있는 keytool이라는 프로그램이 들어있습니다.

 

jdk/bin 폴더에 있는 다양한 프로그램들

그래서 Firebase나 카카오 api 등에서 제공하는 Android 플랫폼의 키 해시 획득 가이드 문서에 이 keytool이라는 프로그램을 활용한 설명이 있는 것이죠. 어떤가요? 이제 퍼즐이 딱딱 들어맞는 느낌이 오시나요?

 

미... 미미!!.jpg

본 포스팅에서는 터미널에서 keytool을 이용해 획득하는 방법과 코드상에서 획득하는 방법에 대해 알려드리겠습니다. 두 방식 모두 동일한 결과값을 리턴하므로 편한 방식으로 사용하시면 되겠습니다.

 

# 코드 상에서 key hash 획득하기

해시 키 획득 방법에 대해 구글링을 해보셨다면 아래와 같은 코드를 많이 보셨을 겁니다.

main() {
	Log.i(TAG, "Key Hash Value :" + getHashKey(this as Activity);
}

public String getKeyHashBase64(Context context) {
      PackageInfo packageInfo = Utility.getPackageInfo(context, PackageManager.GET_SIGNATURES);
      if (packageInfo == null)
          return null;

      for (Signature signature : packageInfo.signatures) {
          try {
              MessageDigest md = MessageDigest.getInstance("SHA");
              md.update(signature.toByteArray());
              return Base64.encodeToString(md.digest(), Base64.DEFAULT);
          } catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException e) {
            e.printStackTrace();
          }
      }
      return null;
  }

위 메서드를 통해 획득한 String 값을 로그에 찍으면 아래와 비슷한 형태의 값을 확인하실 수 있습니다.

getKeyHashBase64 함수의 리턴값을 로그켓으로 확인한 모습

저 해시값은 무슨 키를 해시한 결과일까요? 바로 프로젝트에 설정된 signing key 입니다. 

 

프로젝트 설정 창에서 확인한 signing 설정상태

위 사진은 프로젝트 생성 후 key관련 설정을 하지 않았을 때의 모습입니다. 보시는 것처럼 signing 키가 비어있습니다. 이 경우에 debug.keystore 키를 해시한 값이 리턴됩니다. 이 키는 안드로이드 스튜디오 설치 후 한 번이라도 빌드를 한 경우 자동으로 생성되는 key로서, 모든 PC마다 고유합니다. Path는 리눅스의 경우 ~/.android/debug.keystore, 윈도우즈의 경우 %HOMEPATH%/.android/debug.keystore 입니다.

 

windows 탐색기에 %HOMEPATH%/.android 를 입력한 결과. debug.keystore 파일을 확인할 수 있다.

 

# 터미널에서 키 해시 획득 > 리눅스 기반 터미널

터미널을 실행한 뒤 아래와 같은 명령어를 입력해줍니다.

// 명령어 입력형태
keytool -exportcert -alias [key별칭] -keystore [key경로] | openssl sha1 -binary | openssl base64

// 디버깅 키를 해시하는 경우
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

[key경로] 부분에 해시할 키 path를, [key별칭] 부분에 해당 키의 별칭이 있다면 입력해줍니다. 테스트용으로 debug 키를 해시하는 경우에는 별칭에 androiddebugkey를, 경로에는 ~/. android/debug.keystore를 입력해줍니다.

 

리눅스 기반 터미널에서 디버깅 키를 해시한 모습

디버그 키를 해시하는 경우에는 비밀번호에 그냥 엔터를 입력해주시면 됩니다.

 

# 터미널에서 키 해시 획득 > Windows 기반 터미널

keytool을 사용할 수 있는 상태로 만들어주기

윈도우의 경우에는 jdk/bin 디렉터리를 환경변수 PATH에 설정해주지 않았다면 그냥 터미널에 keytool을 사용하면 알 수 없는 명령어라는 메시지가 나타납니다.

 

이런 경우에는 아래 두 가지 방법 중 하나로 keytool을 사용할 수 있게 해줍니다.

  1. 시스템 > 고급 시스템 설정 > 환경변수 > 시스템 변수의 Path 편집 > jdk/bin 경로 추가
  2. cd 명령어를 통해 jdk/bin 경로로 이동

환경변수 설정 뒤 터미널에서 keytool 명령어를 입력한 모습

 

OpenSSL for Windows Library 설치

여기서 끝이 아닙니다. 저희는 해시된 키의 binary값을 Base64 인코딩으로 표현한 값이 필요하기 때문이죠.

 

너...어는 진짜....

아주 친절한 Windows는 사용자가 손수 설치해주길 원하므로 아래 경로에서 OpenSSL 라이브러리를 설치해줍니다.

(설치 url : https://code.google.com/archive/p/openssl-for-windows/downloads)

 

버전 코드 뒤에 e가 붙은 파일로 다운받아줍시다

여기서 끝이 아니죠. 압축을 풀어보면 openssl 프로그램은 ./bin 디렉토리에 있습니다. 압축을 푼 폴더 전체를 적당한 경로로 옮겨놓고 openssl-0.9.8e_X64\bin 디렉토리 경로를 시스템 환경변수 Path로 잡아줍니다.

 

마지막 2줄을 보면 시스템 환경변수 Path에 jdk/bin 경로와 openssl 경로가 등록된 것을 확인 할 수 있다.

어후 힘들어, 이제 다 됐습니다. 여기까지 잘 따라오셨다면 아래 명령어를 입력해봅시다.

// 디버깅 키를 해시하는 명령어
keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%/.android/debug.keystore | openssl sha1 -binary | openssl base64

윈도우즈.. 너어는... 진짜아... 손이 많이가는 아이구나!?

# 정리

  • 키 해시(Key Hash)는 코드 상의 로그 혹은 터미널을 통해 획득이 가능하다.
  • 터미널에서 획득하는 경우 keytool이라는 jdk/bin 에 포함되어 있는 프로그램과 openssl이라는 프로그램을 사용한다
  • keytool을 통해 해시값을 바이너리 형태로 구하고 openssl을 통해 sha1/base64로 인코딩한다.
  • 리눅스 기반 터미널에서는 jdk가 설치되어 있으면 명령어만 입력해주면 된다.
  • 윈도우 기반 터미널에서는 keytool과 openssl 경로를 System Path에 추가해준 뒤 명령어를 입력해줘야 한다.
  • google openssl 은 k, e, d 버전이 있는데 e 버전을 사용해야 한다.
  • 코드, 리눅스 기반 터미널, 윈도우 기반 터미널 모두 같은 값을 리턴한다.
// 명령어 입력형태
keytool -exportcert -alias [key별칭] -keystore [key경로] | openssl sha1 -binary | openssl base64

// 디버깅 키를 해시하는 경우 (리눅스 기반)
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

// 디버깅 키를 해시하는 경우 (윈도우 기반)
keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%/.android/debug.keystore | openssl sha1 -binary | openssl base64

 

 

 

#3> 마치며


원리는 몰라도 구글링을 통해 원하는 값을 획득하고 개발을 진행할 수 있습니다. 하지만 이런 디테일한 정보까지 알기 원하시는 분들이 계실 것 같아 정리를 해봤습니다. 이 글을 읽는 분들에게 많은 도움이 되었으면 좋겠네요.

 

긴 글 읽어주셔서 감사합니다. 좋은 하루 되십시오.

 


 

하트와 구독 그리고 광고 클릭은 필자에게 큰 힘이 됩니다!

 

댓글