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

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

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