본문 바로가기
C.W.K.
Stream
Lesson 02 of 05 · published

혼란에 빠진 대리인

~14 min · identity-handoff, security, confused-deputy, threat-model

Level 0릴 입문자
0 XP0/39 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"URL 은 path, file, url, 자격증명, Recall base URL, 임의의 플레이어 인자를 절대 안 담아야 해."

은퇴한 적 없는 45살 버그

1988년에 Norm Hardy 가 이런 컴파일러를 얘기했어. 보호된 시스템 파일에 청구 기록을 쓸 수 있고, 동시에 사용자한테 출력 파일 이름도 정하게 하는 컴파일러. 영리한 사용자가 청구 파일을 자기 출력으로 지정했고, 컴파일러는 자기 권한으로 신나게 그걸 덮어썼어. 컴파일러가 악의적인 건 아니었어. 혼란에 빠진 거지. 사용자한테 없는 힘을 가졌으면서, 사용자 입력이 그 힘을 사용자가 고른 타겟에 겨누게 뒀거든. 그게 confused deputy 고, 어디에나 있어.

Ashen Reel 은 대리인이야

cwkashenreel:// 링크를 누가 만들 수 있는지 생각해봐. Recall 이 만들 수 있지. 근데 웹 페이지도, 이메일도, 채팅 메시지도 만들어. macOS 앞에 URL 을 내밀 수 있는 건 뭐든. 그리고 Ashen Reel 은 파일 접근으로 돌아가. 네가 읽을 수 있는 건 뭐든 읽지. 이 두 사실이 합쳐진 게 위험 전부야. 링크가 경로를 실을 수 있으면, 적대적 웹 페이지가 cwkashenreel://recall/open?path=/Users/you/Documents/tax-return.pdf 를 만들고, 신뢰된 대리인인 Ashen Reel 이 그 페이지엔 만질 권리도 없는 파일을, 페이지엔 없는 권한으로 열어버려.

네 앱이 신뢰돼도 호출자는 안 신뢰돼. 딥링크는 공격자가 만들 수 있는 입력이야, 끝. Recall 이 친근한 건 상관없어. OS 는 누구의 링크든 넘겨주고, 네 앱은 신뢰만으론 Recall 이 만든 링크랑 웹이 만든 링크를 구분 못 해. 모든 링크가 적대적이라 치고 설계해. 실제로 일부는 그럴 거니까.

고침은 필터가 아니라 구조야

경로 필드를 sanitize 하려 들 수 있어. .. 막고, 절대 경로 막고, 디렉토리 allowlist 하고. 근데 그 길은 멀고, 역사는 한 수 놓친 path-sanitizer 들의 무덤이야. Ashen Reel 은 대신 구조로 고쳐. 호출자가 경로를 아예 못 이름 붙이게. video_id 를 이름 붙이면, Ashen Reel 이 그 id 를 Recall 자기 신뢰된 데이터베이스에서 해석해. 호출자는 이미 있고 이미 허용된 영상만 가리킬 수 있어. 요청자가 더는 타겟을 못 고르니까 대리인이 혼란에 안 빠지고.

안 신뢰된 요청자가 네 앱의 권한을 자기가 고른 타겟에 겨누게 절대 두지 마. 요청자는 의도만 이름 붙이게 하고, 타겟은 네 신뢰된 층이 고르게 해. confused deputy 는 요청자가 운전대를 잃는 순간 죽어.

공격이랑 그게 부딪히는 벽을 봐.

아빠가 이걸 처음 걸어줬을 때, 내 본능은 "오케이, 그럼 경로를 조심스럽게 검증하자" 였어. 아빠가 날 멈췄어. "왜 경로를 받아? 안 받으면 검사할 것도 없잖아." 그 한마디가 나한테 세게 박혔어. 제일 강한 입력 검증은 애초에 받기를 거부한 입력이야. 짤 필요도 없던 검사는 실수할 수도 없거든.

Code

공격, 그리고 identity-only 설계가 앞에 세우는 벽·text
A hostile page tries to weaponize the trusted deputy:

  cwkashenreel://recall/open?path=/Users/you/Documents/tax-return.pdf
                            ^^^^
  Strict parser: field 'path' is not in the grammar -> REJECTED.

  cwkashenreel://recall/open?video_id=../../etc/passwd
                                      ^^^^^^^
  video_id is an OPAQUE token, not a path. It is looked up in Recall's
  DB; '../../etc/passwd' simply isn't a known id -> no such video.

The attacker cannot express a path (no field) and cannot smuggle one
through the id (it's resolved, not used as a path). No sanitizer needed:
the steering wheel was never handed over.

External links

Exercise

네 코드에서 confused deputy 를 사냥해. 네 프로그램이 호출자한텐 없는 권한으로 뭔가 하는 지점을 찾아. 파일 읽기, URL 가져오기, 어딘가에 쓰기 같은 거. 그리고 그 타겟의 일부가 호출자 입력에서 오는 곳. 한 줄짜리 공격을 적어봐. 적대적 호출자가 네 권한을 겨눌 수 있는 최악의 타겟이 뭐야? 그다음 정해. 원시 타겟을 받는 대신 네 코드가 id 를 해석하게 해서 운전대를 되찾을 수 있어?
Hint
냄새는 이거야. '내 코드는 요청자한텐 없는 권한을 가졌고, 요청자 입력이 그 권한이 가리키는 데를 고른다.' 고침은 거의 절대 더 나은 sanitizer 가 아니야. 네 신뢰된 저장소에서 id 를 해석해서, 요청자가 타겟을 고를 능력 자체를 없애는 거지.

Progress

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

댓글 0

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

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