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

장소가 아니라 사물을 이름 붙이는 URL

~13 min · identity-handoff, capability-security, url-scheme, design

Level 0릴 입문자
0 XP0/39 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Recall handoff 은 identity-only 야. Recall URL 은 video_id 랑 시간을 담지, 경로는 절대 안 담아."

'이거 열어' 의 두 종류

한 프로그램이 다른 프로그램한테 영상 열라고 시키는 방식은 근본부터 두 갈래야. "/some/place/movie.mkv 파일을 열어" 라고 할 수 있어. 장소를 이름 붙이는 거지. 아니면 "Recall 이 v_8f3a… 로 아는 영상을 열어" 라고 할 수 있어. 사물을 이름 붙이는 거고. 비슷해 보여도, 호출자가 뭘 할 수 있느냐로 보면 천지 차이야.

장소를 이름 붙이면 호출자한테 파일시스템 전체를 움직일 지렛대를 쥐여줘. 사물을 이름 붙이면 딱 하나의 권리만 줘. 이 알려진 영상 하나를 열 권리. Ashen Reel 은 늘 두 번째야. 딥링크는 불투명한 video_id 를 실어. Recall 한텐 뭔가를 뜻하고 다른 누구한텐 아무것도 안 뜻하는 토큰이지. 거기에 선택적 타임스탬프 하나. 그게 어휘의 전부야.

불투명하다는 건 호출자가 아무것도 못 배운다는 뜻이야

video_id 는 일부러 불투명해. 경로도 아니고, 파일명도 아니고, 그걸 역으로 풀어 하나 만들 수도 없어. id 를 쥔 호출자는 그 영상을 열어달라고 할 순 있어도, 그게 어디 사는지는 하나도 못 알아내고, id 를 다른 파일 요청으로 바꿔치기도 못 해. 어디라는 정보는 Recall 데이터베이스 안, 있어야 할 자리에 잠겨 있고.

사물을 열 권리를 줘, 장소를 열 권리는 절대 주지 마. capability 는 쥔 사람이 뭘 건드려도 되는지를 이름 붙여. handoff 가 사물 대신 장소를 이름 붙이는 순간, 넌 원하던 방 하나 대신 건물 통째 열쇠를 넘긴 거야.

규율은 요청 타입 자체에서 드러나. 흥미로운 건 그게 뭘 담기를 거부하느냐야.

이게 capability 기반 보안의 축소판이야. capability 는 특정하고 좁은 권리를 주는, 위조 못 하는 토큰이야. video_id 가 딱 그거고. '이 영상 하나 재생' 만 허락하고 그 외엔 아무것도 안 하지. 앱끼리 주고받는 메시지를 capability 로 설계해. 이름 붙은 사물에 대한 좁은 권리 말이야. 그럼 오용의 통째 클래스가 아예 들어올 길이 없어.

보상은 더 작은 폭발 반경이야

악의적 링크가 할 수 있는 최악이 "Recall 이 이미 아는 영상을 열어" 뿐이면, 피해 상한이 구조적으로 낮아. 순회할 경로가 없고, 아카이브 밖에 닿을 파일도 없고, 요청에 시스템 파일을 몰래 끼워넣을 방법도 없어. 설계가 그 공격들을 막는 검사를 '추가' 한 게 아니야. 그걸 표현할 어휘를 아예 '없앤' 거지. 그게 제일 강한 보안이야. 문에 경비를 세운 게 아니라, 위협이 못 지나갈 만큼 좁은 문.

Code

요청 타입. 보안은 이게 뭘 담기를 거부하느냐에 있어·swift
/// What a Recall deep link is allowed to say. Note what is NOT here.
struct RecallOpenRequest {
    let videoID: String       // opaque: meaningful only to Recall
    let timestampMs: UInt64   // optional in the URL, defaults to 0

    // There is deliberately NO `path`, NO `host`, NO `recallBaseURL`,
    // NO `playerArgs`. The request names a video; it cannot name a file.
    // You cannot express 'open /etc/passwd' in this type -- there is no
    // field to put it in. The vocabulary itself is the boundary.
}

// A caller builds:  cwkashenreel://recall/open?video_id=v_8f3a&timestamp_ms=41000
// A caller CANNOT build: ...?path=/anything  -- the parser has no such field.

External links

Exercise

네 시스템에서 한 컴포넌트가 다른 컴포넌트한테 뭘 조작할지 알려주는 API 나 메시지 포맷을 봐. 그게 사물을 이름 붙여, 장소를 이름 붙여? 사물은 수신자가 해석하는 id, 장소는 호출자가 직접 주는 경로나 URL 이나 쿼리나 파일이야. 원시 타겟을 이름 붙인다면, 호출자가 보낼 수 있는 제일 적대적인 값을 상상해봐. 그다음 수신자가 해석하는 불투명 id 를 싣게 메시지를 다시 설계해. 어떤 공격이 표현 자체가 불가능해져?
Hint
판단법. 호출자가, 수신자라면 스스로는 절대 안 골랐을 걸 이름 붙일 수 있어? 그럼 넌 장소를 넘기는 거야. 수신자가 자기 신뢰된 저장소에서 찾아보는 id 로 바꿔. 그럼 호출자는 이미 있고 이미 허용된 것만 가리킬 수 있어.

Progress

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

댓글 0

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

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