본문으로 건너뛰기
중급약 35분

권한·프라이버시 검증 — 요청 흐름 시나리오와 선언 대 실제 동작 대조

권한은 팝업 하나가 아니라 상태 기계다. Android 런타임 권한의 허용·거부·영구 거부·설정 복귀 경로와 iOS 권한 다이얼로그를 시나리오로 나눠 검증하고, Google Play 데이터 안전 섹션과 App Store의 App Privacy 라벨·프라이버시 매니페스트가 실제 네트워크 트래픽·SDK 구성과 일치하는지 대조하는 방법을 익힌다. 불일치를 정책 위반 결함으로 보고하는 서식까지 다룬다.

  • #권한테스트
  • #프라이버시
  • #데이터안전섹션
  • #AppPrivacy
  • #런타임권한

개념

권한은 팝업이 아니라 상태 기계다

"카메라 권한 테스트했어?"라는 질문에 "네, 팝업 뜨고 허용하면 카메라 켜집니다"라고 답하면 테스트의 10%만 한 것이다. 권한은 여러 상태를 오가는 상태 기계 이고, 각 상태에서 앱이 무엇을 보여 주는지가 모두 검증 대상이다.

                  ┌──────────────┐
                  │  요청 전(미결정) │
                  └──────┬───────┘
                         │ requestPermissions()
            ┌────────────┴────────────┐
            ▼                         ▼
      ┌──────────┐              ┌──────────┐
      │   허용    │              │   거부    │
      └────┬─────┘              └────┬─────┘
           │                         │ 다시 요청
           │                         ▼
           │                   ┌───────────────┐
           │                   │ 영구 거부       │
           │                   │ (다이얼로그 안뜸)│
           │                   └───────┬───────┘
           │                           │ 설정에서 변경
           ▼                           ▼
      ┌────────────────────────────────────┐
      │ 앱 실행 중 설정에서 권한 회수 → 프로세스 재시작 │
      └────────────────────────────────────┘

여기에 Android 11 이상의 자동 권한 재설정 (오래 쓰지 않은 앱의 권한을 시스템이 회수), 위치 권한의 대략/정확 선택, 이번만 허용 옵션까지 더해지면 경로가 더 늘어난다. iOS도 마찬가지로 "다음에 물어보기", "앱을 사용하는 동안만", 사진 라이브러리의 제한된 접근(선택한 사진만) 같은 중간 상태를 갖는다.

최소한 이 시나리오는 돌린다

권한마다 아래 표를 채운다. 빈칸이 그대로 결함 후보다.

#시나리오기대 동작의 기준
P1최초 요청에서 허용기능이 즉시 동작. 재요청 팝업이 다시 뜨지 않음
P2최초 요청에서 거부기능이 막히되 앱이 죽지 않고 , 왜 필요한지와 다음 행동을 안내
P3거부 후 같은 기능을 다시 시도사유 설명(rationale) 화면을 먼저 보여 주고 재요청
P4영구 거부(다이얼로그가 더 이상 안 뜸)시스템 설정으로 이동하는 안내·버튼 제공
P5설정에서 허용으로 바꾸고 앱 복귀재시작 없이 기능이 열림. 화면 상태가 깨지지 않음
P6사용 중 설정에서 권한 회수프로세스가 재시작되는 것을 전제로, 복귀 시 데이터 유실·크래시 없음
P7권한 없이도 되는 기능권한과 무관한 기능이 함께 막히지 않는지
P8권한 요청 문구목적이 구체적인가. 플랫폼 문구 요건을 충족하는가

P2와 P7이 가장 자주 깨진다. 권한을 거부하면 앱이 아무 설명 없이 빈 화면을 보여 주거나, 사진 권한 하나 거부했다고 앱 전체가 잠기는 식이다. 이건 사용성 결함이면서 동시에 심사 리스크 다 — 스토어는 "권한을 주지 않으면 앱을 못 쓰게 만드는" 설계를 좋아하지 않는다.

Android — 실습으로 상태를 만들어 낸다

수동으로 앱을 지웠다 깔았다 하면 시간이 오래 걸린다. adb 로 상태를 직접 만든다.

# 현재 권한 상태 보기
adb shell dumpsys package com.example.app | grep -A 40 "runtime permissions"
 
# 권한 회수 / 부여 (앱 프로세스가 재시작될 수 있다 — 그게 P6 시나리오다)
adb shell pm revoke com.example.app android.permission.CAMERA
adb shell pm grant  com.example.app android.permission.CAMERA
 
# 앱의 모든 런타임 권한과 상태를 초기화 (P1을 다시 만들기)
adb shell pm reset-permissions
 
# 위치: 정확/대략 조합 확인
adb shell pm grant com.example.app android.permission.ACCESS_COARSE_LOCATION
adb shell pm revoke com.example.app android.permission.ACCESS_FINE_LOCATION
 
# 앱이 선언한 권한 전체 목록 (매니페스트에 뭐가 들어 있는지)
adb shell dumpsys package com.example.app | grep "android.permission"

pm reset-permissions 는 테스트 반복에 특히 유용하다. 앱 재설치 없이 "처음 설치한 사용자" 상태로 돌아간다.

영구 거부 상태 는 Android 11 이상에서 한 번의 거부로도 진입할 수 있다(같은 권한을 두 번 거부하면 시스템이 더 이상 묻지 않는다). 이 상태를 만든 뒤 앱이 설정 이동 안내를 제대로 주는지 확인한다.

알림 권한은 이제 런타임 권한이다

Android 13(API 33)부터 POST_NOTIFICATIONS 가 런타임 권한이 되었다. 신규 설치 앱은 알림이 기본 꺼짐 이다. 타깃 API 33 이상인 앱은 언제 다이얼로그를 띄울지 직접 정할 수 있고, 타깃이 32 이하면 알림 채널을 만들거나 첫 알림을 만든 뒤 처음 액티비티가 시작될 때 시스템이 자동으로 띄운다 — 대개 앱 첫 실행 순간이라 사용자가 맥락 없이 거부하기 쉽다.

QA가 확인할 것:

  • 다이얼로그가 맥락 있는 시점 에 뜨는가(주문 완료 직후, 알림 설정을 켠 직후 등). 첫 실행 스플래시에서 무턱대고 뜨면 거부율이 올라간다
  • 거부했을 때 앱이 알림 의존 기능(예: 주문 상태 안내)을 어떻게 대체하는가
  • 거부 상태에서 서버가 푸시를 보내면 어떻게 되는가(레슨 3)
  • 업그레이드 사용자(기존에 알림 채널이 있던 앱)는 권한이 자동 부여되는데, 그 경로도 확인했는가

선언과 실제를 대조한다 — 이 모듈의 핵심 작업

권한 팝업 검증은 앱 안쪽 이야기다. 더 중요한 것은 우리가 스토어에 선언한 내용과 앱이 실제로 하는 일이 같은가 다. 여기가 어긋나면 반려를 넘어 앱 삭제·계정 제재로 이어진다.

Google Play 데이터 안전 섹션

모든 개발자는 앱이 사용자 데이터를 어떻게 수집·처리하는지 선언해야 한다. 선언 항목의 뼈대는 이렇다.

선언 항목무엇을 묻는가대조 방법
데이터 수집 여부·유형어떤 유형(위치·개인정보·금융 등)을 수집하는가프록시로 나가는 요청 본문을 본다
데이터 공유 여부제3자에게 전송하는가요청의 목적지 도메인 목록을 본다
전송 중 암호화수집하는 데이터가 모두 암호화 전송되는가평문 HTTP 요청이 하나라도 있는지 본다
데이터 삭제 요청 경로사용자가 삭제를 요청할 수 있는가앱·웹에서 실제로 그 경로가 동작하는지 따라가 본다
아동 대상 정책Play Families 정책 준수 여부연령 게이트·광고 설정 확인
독립 보안 검토MASA(OWASP MASVS 기반) 평가 선언 여부선택 항목. 선언했다면 증빙 유효기간 확인

핵심은 SDK다. 개발자가 직접 쓴 코드는 선언을 잘 하는데, 광고·분석·크래시 리포팅 SDK가 뒤에서 보내는 데이터를 빠뜨린다. Play의 선언 의무는 라이브러리·SDK·웹뷰를 통해 기기 밖으로 나가는 데이터까지 포함한다.

App Store의 App Privacy 라벨과 프라이버시 매니페스트

애플 쪽은 두 축이다.

  1. App Privacy 라벨(영양성분표) — App Store Connect에 데이터 유형과 용도, 사용자 식별 연결 여부, 추적 목적 사용 여부를 입력하면 스토어 페이지에 표로 노출된다.
  2. 프라이버시 매니페스트(PrivacyInfo.xcprivacy) — 앱과 서드파티 SDK가 수집하는 데이터 유형, 추적 도메인, 그리고 필수 사유 API(required reason API) 의 사용 사유를 기계가 읽을 수 있는 형태로 기술한다. 2024년 5월 1일부터 필수 사유 API 사용을 매니페스트에 기술하지 않은 앱은 App Store Connect에서 접수되지 않는다.

필수 사유 API는 기기 지문(fingerprinting)에 악용될 수 있는 API들이다. 파일 타임스탬프, 시스템 부팅 시각, 남은 디스크 공간, 활성 키보드 목록, UserDefaults 접근이 대표적이다. QA가 코드를 직접 고칠 일은 아니지만, 빌드 산출물에 매니페스트가 실제로 들어 있는지, SDK를 추가·업데이트한 뒤에 갱신했는지 는 릴리스 체크 항목이다. 누락 시 업로드 단계에서 경고나 오류로 돌아온다.

대조 실습 — 프록시로 실제 트래픽을 본다

선언 대조는 문서만 봐서는 못 한다. 실제 트래픽을 봐야 한다. 모듈 16 레슨 5·6에서 다룬 보안 도구 사용 감각이 여기서 그대로 쓰인다.

1. 실기기(또는 에뮬레이터)에 프록시(Charles/mitmproxy/Burp) 인증서를 설치한다
2. 앱을 삭제 후 재설치해 "처음 실행" 상태를 만든다
3. 아무 권한도 주지 않은 상태에서 앱을 열고 5분간 기본 플로우만 쓴다
4. 나가는 요청을 도메인별로 묶는다
      - 우리 서버 도메인
      - 알려진 분석/광고/크래시 SDK 도메인
      - 처음 보는 도메인  ← 가장 중요한 발견
5. 각 요청의 본문에서 다음을 찾는다
      - 광고 ID, 기기 식별자, 설치 ID
      - 위치 좌표, 연락처, 설치된 앱 목록
      - 이메일·전화번호 등 직접 식별 정보
6. 발견한 항목을 데이터 안전 섹션 / App Privacy 라벨과 1:1 대조한다

주의: 앱이 인증서 피닝을 쓰면 프록시에서 트래픽이 안 보인다. 그 경우 디버그 빌드나 피닝 예외 빌드를 개발팀에 요청한다. 피닝을 우회하는 도구를 프로덕션 빌드에 쓰는 것은 별개의 위험 이므로 팀 합의 아래에서만 한다.

불일치를 찾으면 일반 결함이 아니라 정책 위반 결함 으로 보고한다. 서식이 달라야 한다.

제목: [정책] 데이터 안전 선언에 없는 기기 식별자가 분석 SDK로 전송됨
 
정책 근거: Google Play 데이터 안전 섹션 — SDK를 통해 기기 밖으로
           전송되는 데이터도 선언 대상
현재 선언: "기기 또는 기타 ID" 수집 = 아니오
실제 동작: 앱 최초 실행 직후, 권한 미부여 상태에서
           POST https://<분석SDK도메인>/v1/events
           body: {"adid":"...", "android_id":"...", "app_set_id":"..."}
재현: 앱 삭제 → 설치 → 실행 → 권한 전부 거부 → 프록시 로그 확인 (10회 중 10회)
영향: 선언 불일치. 정책 위반 시 앱 내림·업데이트 차단 가능
권고: 선언을 수정하거나 SDK 설정에서 식별자 수집을 끈다

권한과 프라이버시를 한 장으로 묶는 표

릴리스마다 이 표를 갱신하면 심사 대응이 훨씬 쉬워진다.

권한/데이터왜 필요한가(기능)요청 시점거부 시 대체 동작선언 위치최근 확인일
카메라QR 결제결제 화면 진입 시번호 직접 입력 제공Play: 아니오(수집 안 함) / Apple: 미수집2026-09-20
정확한 위치주변 매장 찾기매장 찾기 탭 진입 시지역 직접 선택Play: 위치-대략/정확 수집2026-09-20
알림주문 상태 안내첫 주문 완료 직후앱 내 배지로 안내해당 없음2026-09-20
광고 ID캠페인 성과 측정해당 없음(SDK)—Play: 기기 ID 수집·공유2026-09-20

"왜 필요한가" 열을 채우지 못하는 권한이 있다면, 그 권한은 삭제 후보 다. 쓰지 않는 권한이 매니페스트에 남아 있으면 심사 질문을 부르고 설치 전환율도 떨어뜨린다.

실무에서 왜 필요한가

권한 거부 경로는 실제 사용자에게 매우 흔한 상태인데 테스트에서는 거의 안 다뤄진다. QA는 보통 "허용"을 눌러야 다음 테스트를 진행할 수 있으니 습관적으로 허용을 누르고, 그러는 사이 거부 상태의 앱이 어떻게 보이는지 아무도 모르게 된다. 알림 권한이 런타임 권한이 된 뒤로는 이 문제가 매출에 직접 닿는다 — 거부율이 높으면 리텐션 캠페인 전체가 무력해진다.

선언 대조는 더 직접적이다. 데이터 안전 선언이 실제와 다르면 업데이트가 막히거나 앱이 내려간다. 이 위험을 릴리스 전에 발견할 수 있는 사람은 앱을 실제로 돌려 보면서 트래픽을 확인하는 QA 뿐이다. 개발자는 자기 코드는 알지만 SDK가 뒤에서 무엇을 보내는지 모르는 경우가 많다.

채용시장에서의 위치

"권한 테스트 어떻게 하세요"는 모바일 QA 면접의 단골 질문이다. 팝업만 이야기하면 평범하고, 상태 기계와 P1~P8 시나리오, adb pm reset-permissions 같은 실행 수단, 선언 대조까지 말하면 확실히 구분된다. 개인정보 관련 규제가 강해지면서 프라이버시 대조 경험은 금융·헬스케어 앱 QA 채용에서 특히 값이 붙는다.

실습 과제

과제 1 — 권한 상태 기계 실습 (20분)

임의의 앱(사진·카메라·위치 권한을 쓰는 것이면 무엇이든) 하나를 골라 adb 로 P1~P6 상태를 직접 만들고, 각 상태에서 앱 화면을 캡처한다.

adb shell pm reset-permissions
# 앱 실행 → 권한 거부 → 화면 캡처
adb shell pm revoke <package> android.permission.CAMERA

각 상태에서 사용자가 다음에 무엇을 해야 하는지 화면만 보고 알 수 있는가 를 판정하고, 알 수 없는 상태를 결함으로 적는다.

과제 2 — 선언 대조 미니 감사 (25분)

앱 하나를 골라 프록시를 붙이고, 최초 실행 5분 동안 나가는 요청의 목적지 도메인 목록 을 만든다. 그중 우리 서비스 도메인이 아닌 것을 표시하고, 그 도메인이 어떤 SDK인지 조사한다. 그 결과를 스토어 페이지의 데이터 안전 섹션(또는 App Privacy 라벨)과 대조해 일치·불일치·판단 불가로 분류한다. 불일치가 하나라도 있으면 본문의 정책 위반 결함 서식으로 한 건을 작성한다.

과제 3 — 권한 한 장 표 만들기 (15분)

본문의 "권한과 프라이버시 한 장 표"를 자신이 맡은 앱으로 채운다. 매니페스트(또는 Info.plist)에 선언된 권한을 전부 나열한 뒤, "왜 필요한가"를 채우지 못하는 권한을 찾아 제거 제안 목록을 만든다.

자가 체크리스트

  • 권한을 상태 기계로 그리고 최소 6개 이상의 상태·전이를 말할 수 있다
  • P1~P8 시나리오를 권한별로 적용해 테스트 케이스를 만들 수 있다
  • adb 로 권한을 부여·회수·초기화해 원하는 상태를 재현할 수 있다
  • POST_NOTIFICATIONS 가 도입된 Android 버전과 타깃 API에 따른 동작 차이를 설명할 수 있다
  • Play 데이터 안전 섹션의 주요 선언 항목을 나열하고 각각을 무엇으로 대조할지 말할 수 있다
  • App Privacy 라벨과 프라이버시 매니페스트의 차이, 필수 사유 API의 의미를 설명할 수 있다
  • 프록시로 앱의 외부 전송 도메인을 목록화하고 SDK 유래 트래픽을 식별할 수 있다
  • 선언 불일치를 정책 근거·재현 절차·영향이 포함된 결함으로 보고할 수 있다

흔한 실수

  • 허용만 누르고 테스트를 진행한다. 거부·영구 거부 경로가 통째로 미검증으로 남는다. 테스트 데이터 준비 단계에 pm reset-permissions 를 넣어 습관화한다.
  • 권한 팝업만 보고 선언은 안 본다. 앱 안에서 아무 문제가 없어도 선언 불일치로 앱이 내려갈 수 있다. 릴리스마다 선언과 SDK 목록을 함께 검토한다.
  • SDK가 보내는 데이터를 우리 데이터가 아니라고 생각한다. 정책상 기기 밖으로 나가는 모든 데이터가 선언 대상이다.
  • 알림 권한 다이얼로그를 첫 실행에 띄운다. 사용자가 맥락 없이 거부하고, 이후 다이얼로그를 다시 띄울 수 없다. 요청 시점 자체를 검증 항목으로 삼는다.
  • 매니페스트에 안 쓰는 권한을 남겨 둔다. 심사 질문을 부르고, 설치 화면에서 사용자 불신을 키운다.
  • 프록시에서 트래픽이 안 보이면 "전송이 없다"고 결론 낸다. 인증서 피닝일 가능성이 크다. 개발팀에 피닝 여부를 확인하고 테스트 빌드를 요청한다.

참고 자료

낯선 말 풀이

이 레슨에 나온 약어입니다. 본문에서도 처음 나올 때 점선으로 표시해 두었습니다 (제목과 링크 글자는 그대로 둡니다).

API — 응용 프로그램 인터페이스
프로그램끼리 주고받는 창구. 사람이 화면 버튼을 누르는 대신, 프로그램이 정해진 주소로 요청을 보내 답을 받는다.
QA — 품질보증
만든 것이 쓸 만한지 확인하고, 애초에 덜 망가지게 만드는 방법을 정하는 일. "테스트"는 그 일의 일부다.
HTTP — 하이퍼텍스트 전송 규약
웹에서 요청과 응답을 주고받는 약속. "무엇을 달라"고 보내면 "여기 있다" 또는 "그런 건 없다"가 돌아온다.
OWASP — 오왁스프
웹과 앱 보안 자료를 공개로 만드는 비영리 단체. 취약점 목록과 점검 기준이 유명하다.
MASVS — 모바일 앱 보안 검증 표준
휴대전화 앱이 갖춰야 할 보안 요구사항을 정리한 기준.
SDK — 소프트웨어 개발 도구 모음
어떤 기능을 쓰려고 할 때 필요한 도구와 코드를 묶어 둔 꾸러미.
ID — 식별자
무엇 하나를 다른 것과 구별하기 위해 붙인 이름이나 번호.

용어집 전체 보기