본문 바로가기
C.W.K.
Lesson 04 of 06 · published

권한은 해시를 따라가

~14 min · tcc, accessibility, code-signing, designated-requirement, war-story

Level 0Idle Hands
0 XP0/39 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"ad-hoc 요구사항엔 코드 해시가 들어 있어. 그래서 네이티브 코드를 바꿔서 다시 빌드하면, 경로가 같아도 예전 권한이 무효가 될 수 있어." — Tinker README

권한은 누가 받아

테스트용 앱을 진짜로 숨기려면 랩엔 Accessibility 권한을 가진 프로세스가 필요해. 끌리는 지름길은 테스트를 돌리는 쪽, 이를테면 공용 Python 실행기한테 권한을 주는 거야. Tinker README는 딱 그걸 금지해. 범용 인터프리터한테 준 권한은 그게 앞으로 돌릴 모든 스크립트한테 준 권한이니까. 대신 랩은 자기 번들 ID와 자기 AppKit 이벤트 루프를 가진 전용 GUI 앱 Tinker Lab Check를 빌드하고, 그 앱한테만 권한을 줘. 아빠가 랩 Mac 시스템 설정의 개인정보 보호 및 보안 › 손쉬운 사용에서 직접 넣어. 개인정보 데이터베이스를 고치는 사람은 없고, permission_needed 영수증을 통과로 세는 일도 없어.

macOS가 앱에 대해 기억하는 것

macOS 개인정보 시스템(TCC)은 권한을 파일 경로로 기억하지 않아. 앱의 지정 요구사항을 기억해. 코드 서명이 들고 다니는 작은 식인데, 앞으로 어떤 버전이 같은 앱으로 쳐지려면 뭘 만족해야 하는지 적혀 있어. 진짜 인증서로 서명한 앱이면 요구사항이 번들 ID와 인증서를 이름으로 대니까, 다시 빌드해서 다시 서명해도 권한이 유지돼. Tinker Lab Check는 ad hoc으로 서명돼. 이름 댈 인증서가 없으니까 요구사항이 코드 해시 자체를 고정해. 소스를 고치고 다시 빌드하면 TCC한테는 다른 앱이야. 경로도 같고, 이름도 같고, 설정 화면엔 여전히 켜져 있는 걸로 보이는데도.

거기서 자라난 레시피

그래서 랩 스크립트엔 모드가 둘이야. --build는 도우미와 테스트용 앱을 빌드하고, Info.plist를 쓰고, ad hoc으로 서명하고, 돌려. --run-built는 있는 번들의 서명을 검사하고, 기록용으로 지정 요구사항과 실행 파일의 SHA-256을 찍고, 바이트 하나 다시 빌드하거나 서명하지 않고 돌려. 일하는 순서는 이래. 한 번 빌드하고, 아빠가 바로 그 번들에 권한을 주고, 네이티브 코드가 진짜로 바뀔 때까진 늘 --run-built. 바뀌면 일부러 다시 빌드하고 권한을 다시 부탁할 걸 각오해.

켰는데 안 먹힌 토글

한 번은 더 꼬였어. 다시 빌드한 뒤 아빠가 설정에서 도우미를 켰는데 AXIsProcessTrusted()가 계속 false였어. 시스템 로그를 보니 TCC는 새 해시에 'Allowed' 갱신을 적어 놓고, 접근 검사는 계속 옛 해시를 보고 있었어. 고친 건 뭘 초기화하는 게 아니었어. 아빠가 손쉬운 사용 목록에서 Tinker Lab Check 하나만 빼고 같은 현재 번들을 다시 넣었고, 안 바뀐 도우미가 그다음 통과했어. README는 교훈을 정확히 적어 둬. 다른 앱 권한은 초기화하지 말고, 그 재등록과 재시도 사이엔 다시 빌드하지 마. 안 그러면 처음으로 돌아가.

Code

권한 받은 번들을 안 건드리고 돌리기 (scripts/lab-visibility.sh에서)·bash
APP="$PWD/.build/Tinker Lab Check.app"
# After a manual grant, preserve the exact ad-hoc identity Dad approved.
# Native source changes require --build and may need a new console grant.
codesign --verify --deep --strict "$APP"
codesign -dr - "$APP" 2>&1                        # print the designated requirement
shasum -a 256 "$APP/Contents/MacOS/TinkerLabCheck"  # and the executable digest
open -n -W "$APP" --args --result "$RESULT" --parent "$$"
아무 빌드 둘로 차이 직접 보기·bash
# Ad-hoc sign a scratch app twice with a code change in between, and compare.
codesign --force --sign - Scratch.app
codesign -dr - Scratch.app        # designated => cdhash H"…"  (pins this code)

# A certificate-signed app instead shows something like:
# designated => identifier "com.example.app" and certificate leaf = H"…"

External links

Exercise

네 테스트 도우미한테 개인정보 권한이 필요해. 동료가 따라 할 짧은 실행 지침을 써 봐. 도우미를 어떻게 빌드하고 서명하는지, 누가 어디서 권한을 주는지, 권한을 안 깨뜨리고 다시 돌리는 법, 네이티브 코드가 바뀐 뒤 할 일, 그리고 권한이 안 먹히는 것 같을 때 절대 하면 안 되는 한 가지.
Hint
한 번 빌드하고 ad hoc으로 서명해. 사람이 시스템 설정에서 바로 그 번들에 권한을 줘. 다시 돌릴 땐 빌드도 서명도 다시 안 한 번들을 돌려. 코드가 바뀌면 일부러 다시 빌드하고 새 권한을 각오해. 권한이 안 먹히면 로그를 읽고, 그 앱 하나만 뺐다 다시 넣어. 다른 앱 권한 초기화, TCC 데이터베이스 수정, 재등록과 재시도 사이의 재빌드는 절대 하지 마.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인 — 댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.