고유 식별자의 모범 사례

여러분의 애플리케이션이 기기에서 하나의 애플리케이션 인스턴스나 한 명의 인증된 사용자를 식별하는 것이 아니라 한 대의 기기를 식별해야 하는 그럴만한 이유들이 있다고 하더라도, 결국 궁극적인 목표는 (실제의 물리적 기기를 식별하는 것이 아니라) 앱의 특정한 설치를 식별하는 것입니다.

다행히도, Android에서 설치를 식별하는 것은 매우 간단하며 인스턴스 ID를 사용하거나 자신만의 GUID를 설치 시에 만들면 됩니다. 이 문서에서는 여러분의 사용 사례에 따라 애플리케이션에 적합한 식별자를 선택하는 방법에 대해 설명합니다.

Android 권한에 대한 일반적인 내용은 권한 및 사용자 데이터를 참조하세요. Android 권한을 사용하기 위한 구체적인 모범 사례는 앱 권한 모범 사례를 참조하세요.

Android 식별자 사용 시의 원칙

Android 식별자를 사용할 경우 다음 원칙을 따르는 것이 좋습니다.

#1: 하드웨어 식별자의 사용을 피하십시오. SSAID(Android ID) 및 IMEI와 같은 하드웨어 식별자는 필수 기능의 제한 없이 대부분의 사용 사례에서 피할 수 있습니다.

#2: 사용자 프로필 또는 광고 사용 사례에 대해 광고 ID만을 사용하십시오. 광고 ID를 사용할 경우 항상 광고 추적 제한 플래그를 준수하고, 식별자가 개인 식별 정보(PII)에 연결되지 않도록 보장하고, 광고 ID 리셋의 브리지를 피하십시오.

#3: 결제 사기 예방 및 전화통신을 제외한 기타 모든 사용 사례에는 인스턴스 ID 또는 비공개 저장 GUID를 사용하십시오. 거의 대다수의 비광고 사용 사례에서는 인스턴스 ID 또는 GUID만으로 충분합니다.

#4: 자신의 사용 사례에 적합한 API를 사용하여 개인정보 보호의 위험을 최소화하십시오. 고부가 가치의 콘텐츠 보호를 위해서는 DRM API API를 사용하고, 악용 예방을 위해서는 SafetyNet API를 사용하십시오. Safetynet API는 개인정보 보호의 위험을 초래하지 않고 기기의 진위 여부를 확인할 수 있는 가장 쉬운 방법입니다.

이 가이드의 나머지 부분에서는 Android 애플리케이션 개발의 측면에서 이러한 규칙을 상세히 설명합니다.

Android 6.0+에서의 식별자

MAC 주소는 전역적으로 고유하며, 사용자가 리셋할 수 없고, 공장 리셋 시에도 유지됩니다. 사용자 식별을 위해 MAC 주소를 사용하는 것은 어떠한 형태라도 권장되지 않습니다. 이 결과, Android M부터는 로컬 기기의 MAC 주소(예: Wifi 및 Bluetooth)를 타사 API를 통해 사용할 수 없습니다. WifiInfo.getMacAddress() 메서드와 BluetoothAdapter.getDefaultAdapter().getAddress() 메서드는 02:00:00:00:00:00을 반환합니다.

또한, Bluetooth 및 Wifi 스캔을 통해 사용 가능한 인접 외부 기기의 MAC 주소에 액세스하려면 다음 권한을 보유해야 합니다.

메서드/속성 필요한 권한
WifiManager.getScanResults() ACCESS_FINE_LOCATION 또는 ACCESS_COARSE_LOCATION
BluetoothDevice.ACTION_FOUND ACCESS_FINE_LOCATION 또는 ACCESS_COARSE_LOCATION
BluetoothLeScanner.startScan(ScanCallback) ACCESS_FINE_LOCATION 또는 ACCESS_COARSE_LOCATION

광고 ID 사용

광고 ID는 사용자가 리셋할 수 있는 식별자이며 광고 사용 사례에 적합하지만, 사용 시에 명심할 몇 가지 핵심 사항이 있습니다.

광고 ID 리셋 시에 사용자의 의도를 항상 존중하십시오. 사용자 리셋을 브리지하지 마십시오. 즉, 사용자의 동의가 없다면, 더 지속적인 기기 식별자나 지문을 사용하여 이후의 광고 ID를 서로 연결하지 마십시오. Google Play 개발자 콘텐츠 정책에서는 다음과 같이 규정합니다.

...리셋할 경우 사용자의 명시적 동의가 없다면, 이전 광고 식별자에 새 광고 식별자를 연결하거나 이전 광고 식별자로부터 파생되는 데이터에 새 광고 식별자를 연결해서는 안 됩니다.

관련된 맞춤형 광고 플래그를 항상 존중하십시오. 해당 ID에 연결된 추적의 수준을 사용자가 제한할 수 있다는 점에서, 광고 ID는 구성이 가능합니다. 사용자의 의도를 무시하지 않도록 항상 AdvertisingIdClient.Info.isLimitAdTrackingEnabled() 메서드를 사용하십시오. Google Play 개발자 콘텐츠 정책에서는 다음과 같이 규정합니다.

...여러분은 사용자의 ‘관심 기반 광고 옵트아웃’ 또는 '맞춤형 광고 옵트아웃' 설정을 따라야 합니다. 사용자가 이 설정을 활성화한 경우, 여러분은 광고용으로 사용자 프로필을 만들기 위해 또는 맞춤형 광고로 사용자를 타겟팅하기 위해 광고 식별자를 사용하면 안 될 수도 있습니다. 허용되는 액티비티로는 문맥 광고, 노출 빈도 제한(frequency capping), 전환 추적, 보고, 보안 및 사기 감지가 있습니다.

광고 ID와 관련하여 여러분이 사용하는 SDK에 연결된 개인정보 보호정책 또는 보안 정책에 유의하십시오. 예를 들어, Google Analytics SDK mTracker.enableAdvertisingIdCollection(true) 메서드를 사용 중인 경우, 해당하는 모든 Analytics SDK 정책을 검토하고 준수하도록 하십시오.

Google Play 개발자 콘텐츠 정책에서는 또한 “사용자의 명시적 동의가 없다면, 광고 ID를 개인 식별 정보에 연결하거나 지속적 기기 식별자(예: SSAID, MAC 주소, IMEI 등)에 연결해서는 안 된다”고 요구하고 있습니다.

한 가지 예로, 다음과 같은 열의 데이터베이스 테이블을 채우기 위해 정보를 수집한다고 가정해 봅니다.

timestamp ad_id account_id clickid

TABLE-01

account_id name dob country

TABLE-02

이 예에서 ad_id 열은 두 테이블의 account_id 열을 통해 PII와 조인될 수 있으며, 이 경우 여러분이 사용자로부터 명시적 권한을 받지 않았다면 Google Play 개발자 콘텐츠 정책을 위반한 것일 수 있습니다.

이 때 명심할 점은, 광고주 ID와 PII 사이의 링크가 항상 이렇게 명시적이지는 않습니다. PII와 광고 ID 키 테이블에 “유사 식별자”가 동시에 나타날 가능성이 있으며, 이 경우도 문제가 발생합니다. 예를 들어, TABLE-01 및 TABLE-02를 다음과 같이 변경한다고 가정해 봅니다.

timestamp ad_id clickid dev_model

TABLE-01

timestamp demo account_id dev_model name

TABLE-02

이 경우, 클릭 이벤트가 충분히 드물더라도 여전히 이벤트 및 기기 모델의 타임스탬프를 사용하여 TABLE-01 광고주 ID와 TABLE-2에 포함된 PII를 서로 조인시킬 수 있습니다.

이러한 유사 식별자가 데이터 집합에 존재하지 않는다고 확신하기는 어렵지만, 가능한 경우 고유 데이터를 일반화하게 되면 조인에 관련된 대부분의 명확한 위험은 예방할 수 있습니다. 이러한 경우 이 예시에서는 타임스탬프의 정확도가 낮아지므로, 모든 타임스탬프에 대해 동일한 모델을 가진 기기가 여러 대 나타납니다.

기타 솔루션:

  • PII와 광고 ID를 명시적으로 연결하는 테이블을 설계하지 마십시오. 이를 위해 위의 첫 번째 예시에서는 account_id 열을 TABLE-01에 포함시키지 않았습니다.
  • 광고 ID 키 데이터와 PII에 둘 다 액세스하는 사용자나 역할에 대해 액세스 제어 목록을 분리하고 모니터링하십시오. 두 리소스에 동시에 액세스하는 기능(예: 두 테이블 사이의 조인을 수행하기 위해)을 긴밀하게 제어하고 감사한다면 광고 ID 및 PII가 서로 연결될 위험이 줄어듭니다. 일반적으로 액세스 제어란 다음을 의미합니다.
    1. 광고주 ID 키 데이터와 PII의 액세스 제어 목록(ACL)을 분리해서 유지하면, 두 ACL에 있는 개인 또는 역할의 수를 최소화할 수 있습니다.
    2. 또한 이 규칙의 예외를 감지하고 관리하기 위한 액세스 로깅 및 감사를 구현합니다.

광고 ID를 반응형으로 사용하는 방법에 대한 자세한 내용은 광고 ID 도움말 센터 기사를 참조하세요.

인스턴스 ID 및 GUID 사용

기기에서 실행 중인 애플리케이션 인스턴스를 식별하는 가장 단순한 솔루션은 인스턴스 ID를 사용하는 것입니다. 이것은 대다수의 비광고 사용 사례에서 권장되는 솔루션입니다. 인스턴스 ID가 프로비저닝되었던 앱 인스턴스만이 이 식별자에 액세스할 수 있으며, 인스턴스 ID는 앱이 설치되어 있는 동안만 지속되므로 비교적 쉽게 리셋이 가능합니다.

이 결과, 인스턴스 ID는 리셋할 수 없는 기기 범위의 하드웨어 ID에 비해 더 나은 개인정보 보호 속성을 제공합니다. 인스턴스 ID는 또한 메시지 서명(및 이와 유사한 동작)을 위한 키 쌍이 제공되며 Android, iOS 및 Chrome에서 사용이 가능합니다. 자세한 내용은 인스턴스 ID란? 도움말 센터 문서를 참조하세요.

인스턴스 ID가 실용적이 아닌 경우에는 또한 사용자 지정 GUID(Globally Unique Identifier)를 사용하여 앱 인스턴스를 고유하게 식별할 수 있습니다. 이를 위한 가장 간단한 방법은 다음 코드를 사용하여 자신만의 GUID를 생성하는 것입니다.

String uniqueID = UUID.randomUUID().toString();

이 식별자는 전역적으로 고유하므로, 특정 앱 인스턴스를 식별하는 데 사용될 수 있습니다. 여러 애플리케이션 간에 식별자를 연결할 때 발생하는 문제를 피하려면, 외부(공유) 저장소가 아닌 내부 저장소에 GUID를 저장해야 합니다. 자세한 내용은 저장소 옵션 가이드를 참조하세요.

식별자 특성 이해

Android 운영 체제에는 동작 특성이 다른 여러 개의 ID가 있으며, 여러분이 어떤 ID를 사용해야 할지는 여러분의 사용 사례에서 아래의 특성들이 어떻게 작동하는지에 따라 다릅니다. 그러나 이들 특성에는 또한 개인정보 보호도 관련되므로, 이들 특성의 역할을 종합적으로 이해하는 것이 중요합니다.

범위

식별자 범위는 어떤 시스템이 식별자에 액세스할 수 있는지를 나타냅니다. 일반적으로 Android 식별자 범위는 세 가지로 구분됩니다.

  • 단일 앱 - ID는 앱 내부용이며 다른 앱에서는 액세스할 수 없습니다.
  • 앱 그룹 - 사전 정의된 관련 앱 그룹에서 ID에 액세스할 수 있습니다.
  • Rlrl - 기기에 설치된 모든 앱에서 ID에 액세스할 수 있습니다.

식별자에 부여된 범위가 넓을수록, 추적 용도로 사용되는 식별자의 위험이 더 커집니다. 반대로, 하나의 앱 인스턴스만이 식별자에 액세스할 수 있다면, 다른 앱의 여러 트랜잭션 간에 기기를 추적할 때는 식별자를 사용할 수 없습니다.

리셋성 및 지속성

리셋성 및 지속성은 식별자의 수명을 정의하고 식별자의 리셋 방법을 나타냅니다. 일반적인 리셋 트리거로는 인앱 리셋, 시스템 설정을 통한 리셋, 시작 시의 리셋, 설치 시의 리셋 등이 있습니다. Android 식별자의 수명은 다양할 수 있지만, 대개의 경우 이 수명은 ID의 리셋 방법과 관련이 있습니다.

  • 세션 전용 - 사용자가 앱을 다시 시작할 때마다 새 ID가 사용됩니다.
  • 설치-리셋 - 사용자가 앱을 제거하고 다시 설치할 때마다 새 ID가 사용됩니다.
  • FDR-리셋 - 사용자가 기기를 공장 리셋할 때마다 새 ID가 사용됩니다.
  • FDR-지속 - 공장 리셋 시에도 ID가 유지됩니다.

리셋을 통해 사용자는 기존의 프로필 정보로부터 연결이 끊긴 새로운 ID를 만들 수 있습니다. 이것이 중요한 이유는 식별자가 더 길게 더 안정적으로 지속될수록(예: 공장 리셋 등에서) 사용자가 장기적 추적에 노출될 위험성이 더 커지기 때문입니다. 앱 재설치 시에 식별자가 리셋되는 경우에는, ID를 리셋하라는 명시적 사용자 제어가 앱이나 시스템 설정 내에 없더라도, 이 경우 지속성을 줄이고 ID를 리셋할 방법을 제공합니다.

고유성

고유성은 관련된 범위 내에 동일한 식별자가 존재할 확률을 나타냅니다. 기본적으로 GUID(Globally Unique Identifier)는 절대로 충돌하지 않으며 다른 기기/앱에서도 그렇습니다. 그렇지 않은 경우, 고유성 수준은 식별자의 크기와 이 고유성을 생성하는 데 사용되는 임의성(randomness)의 소스에 따라 다릅니다. 예를 들어, 설치 시 Unix 타임스탬프(예: 1445530977)가 삽입된 식별자의 충돌 가능성보다는 설치 시 달력 날짜(예: 2015-01-05)가 삽입된 임의 식별자의 충돌 가능성이 훨씬 더 높습니다.

일반적으로, 사용자 계정 식별자는 고유한 것으로 간주됩니다(즉, 각 기기/계정의 조합마다 고유 ID가 있음). 반대로, 어떤 모집단(예: 기기 모집단) 내에서 식별자의 고유성이 낮을수록, 개별 사용자를 추적하는 것의 유용성은 더 낮으며, 개인정보의 보호 수준은 더 높아집니다.

무결성 보호 및 부인 방지(non-repudiability)

스푸핑이나 재전송 공격을 하기가 어려운 식별자는, 연결된 기기나 계정에 특정 속성이 있음을 입증하는 데 사용될 수 있습니다(예: 가상 기기가 스패머에 의해 사용되지 않음을 입증). 스푸핑을 하기가 어려운 식별자는 또한 부인 방지 기능을 제공합니다. 어떤 기기가 비밀 키로 메시지에 서명한 경우, 다른 누군가의 기기에서 이 메시지를 보냈으며 자신은 이 메시지를 보내지 않았다고 부인하는 것이 어렵습니다. 부인 방지 기능은 어떤 사용자에게는 필요할 수 있으며(예: 결제 인증 시) 어떤 사용자에게는 원치 않는 특성일 수 있습니다(예: 메시지를 보내고 나서 후회하는 경우).

일반적인 사용 사례 및 사용할 식별자

이 섹션에서는 대다수의 사용 사례에서 하드웨어 ID(예: IMEI 또는 SSAID)를 대신하여 사용할 수 있는 대안을 제공합니다. 하드웨어 ID는 사용자가 리셋할 수 없고, 하드웨어 ID 수집에 대한 사용자의 제어가 제한적이기 때문에 권장되지 않습니다.

로그아웃한 사용자 기본 설정 추적

이 경우, 여러분은 기기별 상태를 서버측에 저장하는 중입니다.

권장 사항: 인스턴스 ID 또는 GUID.

권장하는 이유

다시 설치 시까지 정보 지속은 권장되지 않습니다. 왜냐하면 사용자는 앱을 다시 설치하여 자신의 기본 설정을 리셋하고 싶을 수 있기 때문입니다.

로그아웃한 사용자 동작 추적

이 경우, 여러분은 동일 기기상의 다른 앱/세션에서 사용자의 동작에 따라 사용자 프로필을 만들었습니다.

권장 사항: 광고 ID.

권장하는 이유

Google Play 개발자 콘텐츠 정책에 따라 광고 ID를 광고 사용 사례에 사용하는 것은 필수입니다(왜냐하면 사용자가 리셋할 수 있기 때문입니다).

로그아웃한/익명 사용자 분석 생성

이 경우, 여러분은 로그아웃한 사용자와 익명 사용자를 위해 사용 통계와 분석을 측정하는 중입니다.

권장 사항: 인스턴스 ID: 인스턴스 ID가 불충분한 경우에는 GUID를 사용할 수도 있습니다.

권장하는 이유

인스턴스 ID 또는 GUID는 생성된 앱으로 범위가 지정되며, 이 경우 이 ID 또는 GUID는 여러 앱 간의 사용자 추적에는 사용될 수 없습니다. 또한 앱 데이터를 삭제하거나 앱을 다시 설치하여 쉽게 리셋이 가능합니다. 인스턴스 ID 및 GUID를 만드는 것은 매우 간단합니다.

  • 인스턴스 ID 만들기: String iid = InstanceID.getInstance(context).getId()
  • GUID 만들기: String uniqueID = UUID.randomUUID().toString

유의할 점은, 수집 중인 데이터가 익명이라고 여러분이 사용자에게 말한 경우, 여러분은 해당 식별자를 PII(또는 PII에 연결될 수도 있는 다른 식별자)에 연결하지 않을 것임을 보장해야 합니다.

또한 앱별 분석 솔루션을 제공하는 모바일 앱용 Google 애널리틱스를 사용할 수도 있습니다.

로그아웃한 사용자 전환 추적

이 경우, 여러분은 마케팅 전략의 성공 여부를 알아내기 위해 전환을 추적하는 중입니다.

권장 사항: 광고 ID.

권장하는 이유

이것은 광고에 관련된 사용 사례이며 이 경우 다양한 기기 간에 사용 가능한 ID가 필요할 수도 있으므로, 광고 ID를 사용하는 것이 가장 적절한 솔루션입니다.

여러 개의 설치 처리

이 경우, 동일한 사용자의 여러 기기에 앱이 설치된 경우 여러분이 올바른 인스턴스의 앱을 식별해야 합니다.

권장 사항: 인스턴스 ID 또는 GUID.

권장하는 이유

인스턴스 ID는 이 용도로 명시적으로 설계됩니다. 그 범위는 앱으로 제한되므로, 다른 여러 앱 간의 사용자 추적에는 사용될 수 없으며 앱을 다시 설치할 경우 리셋됩니다. 인스턴스 ID가 불충분한 드문 경우에는 GUID를 사용할 수도 있습니다.

사기 예방: 무료 콘텐츠 제한 시행/Sybil 공격 감지

이 경우, 여러분은 한 사용자가 한 대의 기기에서 볼 수 있는 무료 콘텐츠(예: 기사)의 수를 제한하려고 합니다.

권장 사항: 인스턴스 ID 또는 GUID.

권장하는 이유

GUID 또는 인스턴스 ID를 사용할 경우, 이 콘텐츠 제한을 극복하기 위해 사용자는 앱을 강제로 다시 설치해야 하며, 이것은 대부분의 사람들을 단념하게 만들기에 충분합니다. 이 보호 수단이 충분치 않은 경우, Android에서는 콘텐츠 액세스를 제한하는 데 사용되는 DRM API를 제공합니다.

전화통신 및 이동통신사 기능 관리

이 경우, 여러분의 앱이 기기의 전화 및 문자 기능과 상호작용하는 중입니다.

권장 사항: IMEI, IMSI 및 Line1 (Android 6.0(API 레벨 23) 이상에서 PHONE 권한 그룹 필요).

권장하는 이유

전화통신/이동통신사 관련 기능(예: 모바일 이동통신사/SIM 슬롯 간 전환 또는 IP를 통해 SMS 메시지 전송(Line1의 경우) - SIM 기반 사용자 계정)에 필요한 경우, 하드웨어 식별자를 활용하는 것이 적절합니다. 그러나 중요한 점은, Android 6.0+에서는 런타임 권한을 통해서만 이러한 식별자가 사용될 수 있다는 것이며, 사용자가 이 권한을 해제할 수도 있으며 이 경우 여러분의 앱이 이러한 예외를 매끄럽게 처리해야 한다는 것입니다.

악용 감지: 봇 및 DDoS 공격 식별

이 경우, 백엔드 서비스를 공격 중인 여러 대의 가짜 기기를 여러분이 감지하려고 합니다.

권장 사항: Safetynet API.

권장하는 이유

격리된 식별자는 기기의 진위 여부를 나타내기가 어렵습니다. Safetynet API의 SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce) 메서드를 사용하면, 어떤 요청이 진짜 Android 기기(진짜 기기의 반대는, 다른 기기를 스푸핑하는 에뮬레이터 또는 기타 코드)로부터 오는지를 확인할 수 있고, 또한 요청을 수행하는 기기의 무결성을 확인할 수 있습니다. 자세한 내용은 Safetynet API 문서를 참조하세요.

악용 감지: 고부가 가치의 도난당한 자격 증명 감지

이 경우, 여러분은 고부가 가치의 도난당한 자격 증명이 단일 기기에서 (예: 사기 결제를 위해) 여러 번 사용되는지를 감지하는 중입니다.

권장 사항: IMEI/IMSI (Android 6.0(API 레벨 23) 이상에서 PHONE 권한 그룹이 필요).

권장하는 이유

자격 증명을 도난당한 경우, 기기에서 도난당한 자격 증명을 여러 번 사용하여 돈을 빼갈 수 있습니다(예: 토큰화된 신용 카드). 이 시나리오에서는 감지를 피하기 위해 소프트웨어 ID가 리셋될 수 있으므로, 하드웨어 식별자를 사용할 수도 있습니다.