기본 콘텐츠로 건너뛰기

[iOS] Privacy Manifest(PrivacyInfo.xcprivacy)

 Apple App Store는 2024년 5월 1일부터 배포되는 앱(신규, 업데이트 모두)에 대해서 Privacy Manifest 를 포함을 요구하고 있습니다. 아마 저를 포함하는 많은 개발자들이 이 사항을 가지고 머리를 싸매고 있지 않을까 생각이 됩니다. Privacy Manifest를 프로젝트에 포함시키는 것은 기술적으로 어렵지 않고 애플도 비교적 잘 설명된 문서들을 제공하고 있습니다. ( 참고1 , 참고2 ) 그리고, 이미 많은 글에서 이것에 대해서 설명하고 있습니다. 저는 애플의 이러한 정책의 방향성은 훌륭하다고 생각합니다. 요즘 개인정보 관련한 정보 제공 요구가 나날이 강화되고 있는데, 앱 개발자 입장에서 내가 작성한 코드에 대해서는 그나마 알 수 있지만, 요즘과 같이 많은 서드파티 SDK 의존성을 바탕으로 앱을 개발하고 있는 상황에서 각 서드파티 SDK에서 수집되는 정보를 일일이 파악할 수도 없으며, 이들이 이 정보를 이용하는 목적은 더더욱 알기가 어렵기 때문입니다. 그리고, 단순 "수집"이냐 "추적"이냐 까지 파고 들려면, 용어도 어렵고, 정책적 부분이 판단도 애매한 상황에서 개발자가 자신이 개발한 앱에서 수집하는 개인정보에 대해서 모두 제공하는 것은 불가에 가깝습니다. 그래서 앱 스토어에서 "앱이 수집하는 개인정보" 섹션을 채우라고 했을 때는 개인정보를 수집할 것 같은 서드파티들의 기술지원 페이지를 참고해서 항목들을 정리해야하만 했습니다. 이번 애플 정책 요구에서 눈에 띄는것은 각 서드파티에서 제공하는 SDK에도 Privacy Manifest를 포함하도록 요청하고 있습니다. 이로 인해서 개발자는 내가 개발하는 코드에서 수집되는 정보에 대해서 좀 더 집중할 수 있습니다. 다만, 오래된 서드파티 SDK 버전을 사용하는 경우에는 부득이 업데이트를 하거나 대안을 찾거나 하는 피곤한 상황이 생기긴 했습니다.. ^^; 저도 이번 정책 변경으로 개발중인 앱을 요건에 맞게 수정 하는 작업을 진행했습니다.

Admob UMP(Google User Messaging Platform) SDK를 이용한 GDPR(General Data Protection Regulation) 대응

얼마 전 부터 운영중인 앱의 Admob 계정을 들어가면 화면 상단에 아래와 같은 눈에 거슬리는 공지가 표시되기 시작했습니다.


"올해 안에 EEA 및 영국 사용자에게 광고를 게재하는 모든 게시자는 Google에서 인증한 동의 관리 플랫폼(CMP)을 사용해야 합니다. Google의 자체 동의 관리 솔루션을 포함하여 Google에서 인증한 CMP 이면 어떤 것이든 이 목적으로 사용할 수 있습니다. Google의 동의 관리 솔루션을 사용하는 데 관심이 있으면 먼저 GDPR 메시지를 설정하고 UMP SDK를 구현하세요."


유럽쪽 사용자에 대해서 GDPR(General Data Protection Regulation) 동의를 받을 수 있도록 하라는 것이다. GDPR 동의에 대해서 처리해야할 법적인 절차를 잘 모르니 친절한(?) Google의 도움을 받을 수 있다고 하니 받는 것으로 했습니다.


메시지를 보면 구글에서 인증한 동의 관리 플랫폼(CMP)를 사용하거나, 구글에서 제공하는 UMP SDK를 이용해서 구현 하면 된다는 내용입니다.


구글에서 UMP SDK를 제공한다고 하니, 이용하기로 합니다.


UMP SDK는 별도의 SDK 형태로 배포되지 않고, Admob SDK에 포함되어 있고, UMP SDK를 이용하여 구현하는 것은 가이드 페이지에 있는 것을 따라가면 되는 수준이라 여기에서는 생략하도록 합니다.


# 참고 :

- https://support.google.com/admob/answer/10113207

- https://developers.google.com/admob/ios/privacy

- https://developers.google.com/admob/android/privacy

- https://developers.google.com/admob/flutter/eu-consent


저의 경우에는 구현은 어렵지 않게 했으나, 이 것의 동작을 이해하는데 오랜 시간이 필요했습니다.


그 이유는 사용자로부터 개인정보 이용에 대한 동의를 얻지 못했을 때 광고가 노출되지 않는다라는 것과, 수많은 설정중에서 개인화되지 않은 광고에 대한 동의를 얻었음에도 정상적으로 광고가 노출되지 않는 것이었습니다.


앱에 대한 구매 등이 없이 광고를 통해서 수익을 얻고 있는 앱의 입장에서는 사용자로 부터 동의를 얻지 못한 경우에 광고를 노출할 수 없다라는 것은 쉽게 납득할 수 없었습니다. 


법적으로 정확히 어떠한지는 모르겠으나, 인터넷상의 내용으로는 사용자가 동의하지 않더라도 "개인화되지 않은 광고"에 대해서 노출하는 것은 문제가 없는 것으로 보입니다. 그렇다면 내가 뭔가 구현에 빼 먹은 것이 있어서 정상적으로 동작하지 않는다라는 생각에 오랜 고민이 시작되었습니다.


결론은 Admob을 이용하는 경우에는 최소한의 동의를 얻어야 개인화되지 않는 광고를 노출할 수 있습니다.


그렇다면 개인화되지 않은 광고를 노출하기 위해서 왜 최소한의 동의가 필요한 가입니다. 구글 문서가 UMP 이전 SDK인 Funding Choice 문서와 혼재 되어 있어서 가끔 헷갈리게 하는 부분이 있습니다. Funding Choice 당시에는 UMP 와 약간 다르게 동작했던 것 같으나 저로써는 확인할 길이 없으니 문서를 최신 버전으로 갱신하지 않은 구글을 한번 욕하고 넘어 갑니다. 하여튼, 최소한의 동의가 필요한 이유는 구글 문서 상에 아래와 같은 내용으로 알 수 있습니다. (https://support.google.com/admanager/answer/9005435?hl=ko)


"개인 맞춤 광고가 아닌 광고는 광고 타겟팅을 위해 쿠키나 모바일 광고 식별자를 사용하지 않지만, 게재빈도 설정, 통합 광고 보고서, 사기 및 악용 방지를 위해서는 쿠키나 모바일 광고 식별자를 사용합니다. 따라서 법적으로 요구되는 경우에는 이러한 용도를 위해 특정 EEA 국가의 온라인 개인정보보호지침에 따라 쿠키나 모바일 광고 식별자 사용에 대한 동의를 얻어야 합니다."


Admob에서 광고 통계 생성하는 방식으로 인하여 비 개인화된 광고더라도 동의가 필요하다 라는 이야기입니다. 

그럼 UMP에서 최소한의 동의는 무었인가 입니다. 동의 화면을 자유롭게 구성할 수 없기 때문에 사용자가 동의 버튼을 누르지 않고, 최소한의 권한만 허용하겠다라는 생각을 갖게 된다면 광고가 노출되는 조건을 생성하는 것이 쉽지 않습니다.


개인화/비개인화된 광고 노출을 위한 최소의 동의는 UMP 동의 화면을 기준으로 다음과 같습니다. 구글 공식 문서에 설명된 내용이 있는데 링크를 잊어 버렸고, 해당 문서의 내용만으로 좀 부족한 부분이 있으니 아래를 참고하십시오. 


개인화된 광고를 위한 최소한의 동의는 다음과 같습니다.

1. 장치에 정보 저장 및/또는 액세스(목적 1)

2. 개인화된 광고 프로필 만들기(목적 3)

3. 개인화된 광고 선택(목적 4)


정당한 이익(또는 게시자가 요청하도록 CMP를 구성하는 경우 동의)은 Google이 다음을 수행하도록 설정됩니다.

1. 기본 광고 선택(목적 2)

2. 광고 실적 측정(목적 7)

3. 시장 조사를 적용하여 고객 통찰력 생성(목적 9)

4. 제품 개발 및 개선(목적 10)

5. Vendor list에서 Google을 찾아서 허용해야 합니다. (100개가 넘는 리스트에서 Google을 찾아야하는데 알파벳 순이 아니어서 찾기가 어렵습니다.)


비 개인화된 광고 노출을 위한 최소한의 동의는 다음과 같습니다.

1. 장치에 정보 저장 및/또는 액세스(목적 1)


정당한 이익(또는 게시자가 요청하도록 CMP를 구성하는 경우 동의)은 Google이 다음을 수행하도록 설정됩니다.

1. 기본 광고 선택(목적 2)

2. 광고 실적 측정(목적 7) <- 현재 버전에서는 선택하지 않아도 광고 노출됩니다.

3. 시장 조사를 적용하여 고객 통찰력 생성(목적 9) <- 현재 버전에서는 선택하지 않아도 광고 노출됩니다.

4. 제품 개발 및 개선(목적 10) <- 현재 버전에서는 선택하지 않아도 광고 노출됩니다.

5. Vendor list에서 Google을 찾아서 허용해야 합니다. (100개가 넘는 리스트에서 Google을 찾아야하는데 알파벳 순이 아니어서 찾기가 어렵습니다.)


참고 : 

 - https://groups.google.com/g/google-admob-ads-sdk/c/UcveWmtBm4Q/m/Fb-rtp2vAwAJ

 - https://stackoverflow.com/a/64245927


여기까지 보면 사용자에게 전체 동의를 얻지 않는 이상 현실적으로 부분 동의는 받기가 쉽지 않다는 결론이 나옵니다. (구글에서 인증한 CMP를 이용하면 동의 절차가 좀 더 간편한 것 같으나 비용등이 발생할 수 있는것 같습니다.)


그래서 저는 현재 사용자의 동의 상태가 광고를 노출할 수 있는 상황인지 아니면 노출할 수 없는 상황인지를 파악해서 광고가 노출되지 않는 상황에 대해서 대응하는 것으로 방향을 정했습니다.


그럼 이 상황을 파악할 수 있는 방법을 UMP SDK에서 제공하면 가장 쉽게 문제를 해결할 수 있겠으나, UMP에서는 동의가 필요하다, 동의가 필요하지 않다, 동의 했다로만 상태를 확인할 수 있습니다. "동의를 했다" 라는 상태가 사용자가 선택한 옵션의 여부는 중요하지 않고, 동의의 화면에 들어가서 동의를 허가나, 옵션을 바꿔서 동의를 하거나, 거부한 경우를 모두 포함하고 있기 때문에 광고 노출 여부와는 관계가 없기 때문에 현실적으로 도움이 되지 않습니다.


그럼 어떻게 해야하냐는 "구글에서 인증한 CMP"라는 문구에서 힌트를 얻을 수 있습니다. 다른 라이브러리들과 Admob를 다른 SDK와 연동해서 사용할 수 있다는 이야기입니다. 고로, 어딘가 값이 서로 공유하는 위치에 저장되어 있다라는 것입니다. 구글에서는 IAB TCFv2 표준을 만족하는 CMP를 인증하고 있습니다. 


사용자가 동의를 수행하면 SharedPreference/UserDefault 에 해당 설정을 IAB TCFv2 표준에 맞게 저장하고, 이 값을 Admob에서 읽어서 사용하고 있기 때문에 이것을 활용하면 지금 광고를 노출할 수 있는 상황인지를 파악할 수 있습니다.


아래 링크를 보면 선각자(!!!)들이 동일한 작업을 해서 개인화된 광고, 비개인화된 광고를 판단하는 코드를 만들어 놓았으니 이를 참고하면 됩니다.

https://stackoverflow.com/a/68310602 (kotlin/swift), https://stackoverflow.com/a/72777100 (flutter. 이 예시는 약간 수정이 필요합니다.)


이렇게 해서 광고를 보여줄 수 있는 상황인지 까지는 파악할 수 있게 되었습니다. 그럼 광고가 노출되지 않는 상황에서는 어떻게 처리해야할까?


이 부분은 다른 앱들은 어떻게 처리했는지를 참고해 보았습니다. 유럽에 살지 않는 이상 GDPR을 요구하지 않는 상황이라서 제가 직접 겪어 보지 못한 상황들이라서 VPN을 이용해서 광고를 수익원으로 하는 여러 앱들을 써보고 판단하기로 했습니다. 


Case 1. GDPR 동의 없이 그냥 광고를 노출하는 경우. 아직 많은 앱들이 동의 절차를 요구하지 않고 있었습니다. 

Case 2. GDPR 동의를 요구, 부동의 하더라도 광고가 노출됨. (이게 가장 원하는 형태이긴 하나 이런 식으로 구현할 수 있는 광고 네트워크와 CMP를 찾아야 가능하겠습니다.)

Case 3. GDPR 동의를 요구, 부동의시 유료 구매를 요구함. 구매하지 않으면 다시 GDPR 동의를 요구.

Case 4. 별도 GDPR 동의를 요구하지 않음. 대신 이용 약관 동의를 수행해야 사용 가능. 광고 노출됨. (예. 캔디크러시사가)


다만, 각 앱에서 사용하는 광고 네트워크를 알 수 없고, 어떤 CMP를 사용하는지, GDPR 관련해서 적용을 했는지 등 조건이 모두 다르고 알 수 없으니 어디까지나 참고..


구글 문서에 대부분 있는 내용입니다 만, 문서들이 한눈에 들어오지 않아서 간단히 정리해놓겠다고 쓰기 시작했는데 내용이 좀 길어졌습니다.


추가:

Admob에서 "제한적인 광고" 라는 것을 지원한다고 합니다. 사용자가 GDPR 동의 화면에서 옵션 변경으로 들어가서 하나도 선택하지 않고, 동의를 한 경우(기본으로 목적 1에 대한 동의를 얻지 못하고, 몇가지 옵션에 대해서 적법한 이익 또는 동의가 선택되어 있습니다.)에 기본적인 광고는 보여지지 않지만 "제한적인 광고"를 노출할 수 있도록 한다고 합니다.

참고: https://support.google.com/admob/answer/10105530?hl=ko&ref_topic=9756841


그런데 저의 경우에는 노출할 수 있는 광고가 적어서 그런지 광고가 노출되는 경우를 확인하지 못했습니다. 

        


댓글

  1. 자세한 설명과 분석글 감사합니다! 좋은정보 감사합니다!
    만약 서비스중인 앱이 유럽권에 사용자에게 노출중인 Admob 광고가있다면, 위의 GDPR메세지 작성후 UMP SDK를 반드시구현해야할까요? 만약 불이행시 받는 불이익은 어떤것들이 있을까요?

    답글삭제
    답글
    1. 정확히 어떻게 된다라고 구글이 친절하게 설명을 해주질 않아서 저도 잘은 모르겠습니다만, 공지 내용으로 봐서는 24년 1월 16일부터 유럽쪽에서 광고가 게시되지 않을 수 있을 것 같습니다.

      삭제

댓글 쓰기

이 블로그의 인기 게시물

Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:393))

현재 flutter로 개발 중인 프로젝트에서 REST API 통신을 하는데, 안드로이드 단말에서 CERTIFICATE_VERIFY_FAILED 오류가 발생하면서 서버와 통신이 이뤄지지 않는 문제가 발생하였습니다. 현재 상황은 apache 서버에 php를 이용하여 api를 만들었고, 운영서버에는 SSL 이 적용되어 있습니다. SSL 인증서는 공인 인증 기관으로 부터 발급된 인증서를 사용하고 있습니다. iOS에서는 문제없이 서버와 통신이 이뤄지지만 안드로이드에서는 오류가 발생합니다. CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate "CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate"로 검색을 하면 공인 기관에서 발급하지 않고 자체적으로 인증서를 발급받아서 사용하는 경우에 문제 해결 방법들이 검색됩니다. 앱 내부에서만 사용하는 서버인 경우에 자체 발급된 인증서를 많이 쓰는 모양입니다.  자체 인증서로 인한 문제를 해결하는 방법은 두가지 정도가 있는 듯 합니다.  1. 인증서 검증을 하지 않는 방법 Dio dio = new Dio(); (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) { client.badCertificateCallback = (X509Certificate cert, String host, int port) = true; return client; }; 2. 인증서를 내장하는 방법 ByteData data = await rootBundle.load('assets/raw/certificate.pem'); SecurityContext context = SecurityContext.defaultConte

개발자를 확인할 수 없기 때문에 'iproxy'을 열 수 없습니다.

개발자를 확인할 수 없기 때문에 'iproxy'을 열 수 없습니다. 얼마전 iOS 버전 개발을 위해서 macOS / XCode / flutter 버전을 한꺼번에 변경한 일이 있었습니다. 그러는 과정에서  '개발자를 확인할 수 없기 때문에 'iproxy'을 열 수 없습니다.'라는 오류를 접하게 되었습니다. 구글에서 flutter를 배포하면서 애플에서 요구하는 배포 프로세스를 거치지 않다보니 발생하는 문제라고 합니다. flutter 외에 다른 앱에서 발생할 수 있는 문제이기도 하고, 개발환경을 새로 구성해야 하는 상황에서 또 접할 문제라서 기억 차원에서 간략히 메모를 남깁니다. 터미널에서 아래 명령어를 실행해서 macOS의 인증서 검사 절차에서 무시되도록 하면 됩니다. sudo xattr -d com.apple.quarantine /FLUTTER_PATH/bin/cache/artifacts/usbmuxd/iproxy