1. 소개
이 절은 비규범적이다.
저장소는 일반적으로 사용자의 보안과 개인정보를 보호하기 위해 출처별로 분할된다. 이는 올바른 기본값이지만, 어떤 사이트가 요청하든 바이트 단위로 동일한 파일인 매우 크고 널리 사용되며 공개적으로 배포되는 제한적인 종류의 리소스, 즉 AI 모델, WebAssembly 모듈, JavaScript 라이브러리, 게임 엔진 및 대용량 웹 폰트에는 적합하지 않다. 서로 관련 없는 두 출처가 각각 동일한 8GB 모델에 의존하는 경우, 출처별로 분할된 저장소는 사용자가 해당 모델을 두 번 다운로드하여 보관하도록 강제한다. 이는 사용자의 대역폭, 저장 공간, 배터리뿐 아니라 네트워크 전체에도 낭비이다.
교차 출처 저장소(COS)는 URL이 아니라 암호학적 해시를 키로 사용하는 콘텐츠 주소 지정 가능 캐시이며, 사용자 에이전트가 이러한 리소스의 저장된 사본 하나를 사용하기로 선택한 여러 출처 간에 공유할 수 있게 한다. COS에 리소스를 저장하는 행위는 항상 저장 출처가 명시적으로 선택해야 하며, 사용자 에이전트는 리소스를 읽도록 허용되었을 출처에 대해서도 리소스의 존재 확인을 보류할 수 있다. § 7 개인정보 보호 및 보안 고려사항을 참조한다.
이 명세의 진입점은 requestFileHandle()
메서드이며, crossOriginStorage를
통해 노출된다.
const hash= { algorithm: 'SHA-256' , value: '8f434346648f6b96df89dda901c5176b10a6d83961dd3c1ac88b59b2dc327aa4' , }; try { const handle= await navigator. crossOriginStorage. requestFileHandle( hash); const file= await handle. getFile(); // 파일을 사용하여 무언가를 수행한다. } catch ( err) { if ( err. name=== 'NotFoundError' ) { // 교차 출처 저장소에 공개 가능한 형태로 존재하지 않으므로 대신 네트워크에서 가져온다. } }
이 명세는 파일 시스템 표준 [FS]의 FileSystemFileHandle,
FileSystemWritableFileStream
및 관련
기반 구조를 재사용하되, 단일 출처의 비공개 파일 시스템이나 사용자에게 표시되는 파일 시스템이 아니라
전용 교차 출처 공유 파일 시스템으로 범위를 한정한다.
이 명세는 명령형 JavaScript API만 정의한다. 관련 제안은 동일한 기반 캐시를 선언적 마크업과 통합한다.
즉,
link
및
script의
HTML
crossoriginstorage 속성,
crossOriginStorage JavaScript 가져오기 속성, CSS
cross-origin-storage() <request-url-modifier>이며, 각각 해당 호스트
언어의 자체
명세에서 정의한다. § 8 다른 명세와의
통합을 참조한다.
2. 개념
2.1. 해시
- 알고리즘
-
[WEBCRYPTO]에서 인식하는 해시 알고리즘의 이름을 나타내는 문자열이다. 예를 들어 "
SHA-256"이다. - 값
-
문자열로서, 알고리즘이 생성한 다이제스트를 소문자 16진수로 인코딩한 것이다. "
SHA-256"의 경우 길이는 64자이다.
algorithm
사전 멤버의 형식은 HashAlgorithmIdentifier가
아니라 일반
DOMString이다.
값의 범위는 [WEBCRYPTO]의 해시 알고리즘에서
허용하는 이름의 집합과 정확히 같지만 그렇다.
HashAlgorithmIdentifier는
(object or DOMString)이다. 즉, 추가로 object도 허용하며, [WEBCRYPTO]가 이를
Algorithm
형태의
사전으로 정규화하므로, 호출자는 매개변수가 필요한 알고리즘에 추가 매개변수를 전달할 수 있다
(예: {name: "HMAC", hash: "SHA-256"}). 해시 알고리즘은 이러한 매개변수를 받지 않으며,
알고리즘은
단일 연산에서 한 번 소비되는 것이 아니라 콘텐츠 주소 지정 가능
키의 일부로 저장되고 비교되며 왕복 처리된다. 또한 이 명세의 모든 예에서는 단순 문자열을 사용한다.
여기서 임의의 객체를 허용해도 기능은 추가되지 않지만
동등성과 직렬화는
불필요하게 복잡해진다. 따라서 DOMString이 이 필드에 더 좁고 올바른 형식이다.
두 COS 해시 값은 각각의 알고리즘 값이 ASCII 대소문자를 구분하지 않고 일치하며, 각각의 값이 정확히 같으면 동등하다.
참고: 대소문자가 규범적으로 제한되지 않는 알고리즘과 달리, 값은 이미 규범적으로 소문자여야 하므로(위 내용 참조), 비교 시 ASCII 대소문자를 구분하지 않는 비교가 아니라 일반 문자열 비교를 사용한다.
콘텐츠 주소 지정 가능 저장소는 항목의 키로 URL이나 이름이 아니라 COS 해시의 동등성을 사용하는 저장소이다. 동일한 바이트와 동일한 해시 알고리즘을 가진 두 파일은 몇 개의 출처가 저장했는지 또는 몇 개의 URL에서 가져왔는지와 관계없이 동일한 항목이다.
2.2. COS 항목
각 사용자 에이전트에는 하나의 COS 레지스트리가 있으며, 이는 COS 해시 값에서 COS 항목 구조체로의 맵이며, 교차 출처 저장소를 사용하는 모든 출처가 공유한다. COS 항목에는 다음 항목이 있다.
- 해시
- 바이트
-
Null 또는 해시의 알고리즘에 따른 다이제스트가 해시의 값과 같은 바이트 시퀀스이다. 작성자가 검증 및 저장을 완료할 때까지 Null이다.
- 상태
-
"
pending" 또는 "written"이다. 항목은 "pending"으로 시작하며, 바이트가 처음 설정될 때 정확히 한 번 "written"이 된다. - 출처
-
선언된 공유 범위이다. "
*"(모든 출처), 출처 문자열의 목록(해당 출처만), 또는 null(동일 사이트 출처만)이다. 첫 번째 작성자가 설정하며 상향할 수 있지만 하향할 수는 없다. - 저장 출처
-
각각 이 항목의 바이트 쓰기를 한 번 이상 성공적으로 완료한 출처의 집합이다. 페이지를 다시 불러와도 유지되며 시간이 지남에 따라 증가한다. § 5.2 축출에서 설명한 경우를 제외하면 감소하지 않는다. 저장 출처에 포함된 출처는 출처 또는 항목의 해시가 공개 해시 목록(PHL)에 있는지와 관계없이 항상
requestFileHandle()을 통해 해당 항목의 핸들을 얻을 수 있다. § 3.4.1 원래 저장자의 접근을 참조한다.
사용자 에이전트에는 연결된 교차 출처 저장소 큐가 있으며, 이는 새 병렬 큐를 시작한 결과이다. COS 레지스트리에 대한 모든 연산은 이 큐에 대기열에 추가해야 하며, 그러면 해당 연산은 대기열에 추가된 순서대로 실행되고 서로 끼어들지 않는다.
2.3. 공개 해시 목록
교차 출처 저장소에 해시가 존재함을 확인하는 행위 자체가 사용자의 탐색 기록에 관한 정보를
유출할 수 있다(§ 7.2 교차 사이트 탐색 참조). 이는 특히 전역 범위 항목에
대한 위험이다. 출처가 목록이거나 null인 항목은
저장 출처의
명시적인 선택에 의해 공개 범위가 이미 제한되었지만, "*"는 잠재적으로 웹의 모든 출처에
항목을 노출한다. 이 특정 위험을 제한하기 위해 "*" 범위의 리소스는 해시가 추가적인 독립 게이트를
통과하는 경우에만 저장 출처 외부의 출처에 공개할 수 있다. 이 게이트는
공급업체 중립적이고 구현에서 정의하는 COS 해시 값의 허용 목록인
공개 해시 목록
(PHL)의 멤버십이다.
해시는 k-익명성 방식의 인기도 기준을 충족한 후에만 공개 해시 목록에 추가된다. 예를 들어 일정 수 이상의 독립적인
출처에서 바이트 단위로 동일하게 나타나는 경우이다. 그러면 공유 캐시에 존재함을 확인해도 특정 사용자에 관한
정보를 제공하지 않는다.
COS 해시 hash가 사용자 에이전트의 현재 공개 해시 목록 스냅샷의 항목과 동등하면, hash는 공개 해시 목록에 있다.
Public Hash List의 검색 프로토콜, 업데이트 주기, 데이터 형식, 인기 임계값 및 거버넌스는 이 명세의 동반 산출물로서 [URL] 표준의 공개 접미사 목록이 규범적인 문구가 아니라 동반 데이터 파일인 방식과 같은 취지로 상세히 설계되었다 — 이 저장소의 Public Hash List 설명서를 참조하라. 이 설계는 WHATWG에 의한 거버넌스를 제안하며, 공개 접미사 목록의 공급업체 간 협력 및 롤링 릴리스 선례를 모델로 삼고, 독립적으로 확인된 보편성에 기반한 승인 기준을 사용한다 — 이는 위에서 설명한 k-익명성 스타일 기준을 구체적으로 적용한 사례이며, 사용자가 쿼리할 때 사용자 에이전트가 반복적으로 확인하는 검사가 아니라 해시가 승인되는 방식의 일부로 오프라인에서 한 번 적용된다. 이러한 내용은 아직 이 제안 외부에서는 확립되지 않았다. 목록 자체에 대한 초기 비규범적 코드 프로토타입은 이 저장소의 public-hash-list/implementation/에서 유지 관리된다 — 실용적인 임시 위치이며, 전용 공급업체 간 저장소는 PHL 설명서에 설명된 거버넌스 목표로 남아 있다. 이 명세는 해시가 PHL에 있는지에만 의존하며, 특정 검색 메커니즘이나 거버넌스 모델에는 의존하지 않는다. 따라서 해당 설계가 어떻게 발전하더라도 올바른 상태로 유지된다.
3.
CrossOriginStorageManager
인터페이스
[Exposed =(Window ,Worker ),SecureContext ]interface {CrossOriginStorageManager Promise <FileSystemFileHandle >requestFileHandle (CrossOriginStorageRequestFileHandleHash ,hash optional CrossOriginStorageRequestFileHandleOptions = {}); };options dictionary {CrossOriginStorageRequestFileHandleHash required DOMString ;value required DOMString ; };algorithm dictionary {CrossOriginStorageRequestFileHandleOptions boolean =create false ; (DOMString or sequence <DOMString >); };origins interface mixin { [NavigatorCrossOriginStorage SameObject ,SecureContext ]readonly attribute CrossOriginStorageManager crossOriginStorage ; };Navigator includes NavigatorCrossOriginStorage ;WorkerNavigator includes NavigatorCrossOriginStorage ;
각 Navigator
및 WorkerNavigator
객체에는 연결된 CrossOriginStorageManager
객체가 있다. crossOriginStorage getter
단계는 this에 연결된
CrossOriginStorageManager를
반환하는 것이다.
각 CrossOriginStorageManager
객체에는 연결된 출처가 있으며, 객체가 생성될 때
this의 관련 설정 객체의 출처로 설정된다.
3.1. requestFileHandle()
메서드
- handle = await navigator . crossOriginStorage .
requestFileHandle(hash) -
hash로 식별되는 파일이 교차 출처 저장소에 존재하고 호출 출처에 공개할 수 있으면 해당 파일의 핸들을 반환한다. 그렇지 않으면 "
NotFoundError"DOMException으로 거부한다. "NotFoundError"는 파일이 교차 출처 저장소에 물리적으로 존재하지 않음을 증명하지 않는다. § 7.3 가용성 게이팅을 참조한다. 호출자는 이를 "대신 네트워크에서 가져온다"라는 의미로 처리할 수 있다. - handle = await navigator . crossOriginStorage .
requestFileHandle(hash, {create: true }) -
hash로 식별되는 파일을 교차 출처 저장소에 쓰는 데 사용할 수 있는 핸들을 반환하며, 아직 항목이 없으면 동일 사이트 출처로 기본 제한되는 새 항목을 생성한다. 호출자는 항목이 이미 존재했는지와 관계없이 핸들의
createWritable()메서드를 통해 파일의 전체 내용을 써야 한다. 사용자 에이전트는 이 시점에서 작성된 바이트의 해시가 hash인지 검증하며, 그렇지 않으면 "DataError"DOMException으로 거부한다. 이 요구사항은 출처가 생성 요청을 hash가 이미 존재했는지 확인하는 오라클로 사용하는 것을 방지한다. - handle = await navigator . crossOriginStorage .
requestFileHandle(hash, {create: true,origins: "*" }) -
위와 같으며, 추가로 작성이 완료된 뒤 hash 요청이 § 7.3 가용성 게이팅을 통과하는 모든 출처에 항목을 공개할 수 있게 한다.
- handle = await navigator . crossOriginStorage .
requestFileHandle(hash, {create: true,origins: ["https://a.example", "https://b.example"] }) -
위와 같으며, 공개 범위를 나열된 출처로 정확히 제한한다. 호출 출처 및 이미 저장 출처에 포함된 모든 출처도 추가로 허용된다.
requestFileHandle(hash, options)
메서드
단계는 다음과 같다.
-
result를 새 프로미스로 둔다.
-
global에 연결된
Document가 있는 경우 해당 문서가 "cross-origin-storage" 정책 제어 기능을 사용하도록 허용되지 않았다면:-
global이 주어졌을 때 DOM 조작 태스크 소스에 전역 태스크를 대기열에 추가하여 result를 "
NotAllowedError"DOMException으로 거부한다. -
result를 반환한다.
-
-
validationFailure를 hash와 options가 주어졌을 때 COS 요청 검증을 실행한 결과로 둔다.
-
validationFailure가 null이 아니면:
-
global이 주어졌을 때 DOM 조작 태스크 소스에 전역 태스크를 대기열에 추가하여 result를 validationFailure로 거부한다.
-
result를 반환한다.
-
-
다음 단계를 교차 출처 저장소 큐에 대기열에 추가한다.
-
result를 반환한다.
CrossOriginStorageRequestFileHandleHash
hash와
CrossOriginStorageRequestFileHandleOptions
options가 주어졌을 때 COS
요청을 검증하려면 null 또는 TypeError를
반환한다.
-
hash["
algorithm"]이 [WEBCRYPTO]에서 인식하는 해시 알고리즘 이름이 아니면 새TypeError를 반환한다. -
hash["
value"]가, hash["algorithm"]이 "SHA-256"과 ASCII 대소문자를 구분하지 않고 일치할 때 정규식/^[0-9a-f]{64}$/과 일치하지 않으면 새TypeError를 반환한다.참고: 향후 해시 알고리즘은 서로 다른 예상 다이제스트 길이를 정의할 수 있다. 이 명세는 예제 전체에서 사용되는 "
SHA-256"만 규범적으로 제한한다. -
null을 반환한다.
3.2. 파일 읽기
-
entry를 COS 레지스트리에서 해시가 hash와 동등한 COS 항목이 있으면 해당 항목으로, 그렇지 않으면 null로 둔다.
-
entry가 null이 아니고 entry의 상태가 "
pending"이면:-
global이 주어졌을 때 DOM 조작 태스크 소스에 전역 태스크를 대기열에 추가하여 result를 "
NotAllowedError"DOMException으로 거부한다. -
반환한다.
참고: 쓰기가 진행 중인 해시는 의도적으로 존재하지 않는 해시와 다르게 동작한다. 이를 통해 호출자가 진행 중인 쓰기를 실제 캐시 미스로 오인하고, 오직 해당 파일을 쓰기 위한 목적으로 매우 큰 파일의 중복 동시 다운로드를 시작하지 않도록 한다. § 3.3 파일 생성 및 쓰기를 참조한다.
-
-
disclosableEntry를 entry와 origin이 주어졌을 때 가용성 게이팅 적용을 실행한 결과로 둔다.
-
disclosableEntry가 null이면:
-
global이 주어졌을 때 DOM 조작 태스크 소스에 전역 태스크를 대기열에 추가하여 result를 "
NotFoundError"DOMException으로 거부한다. -
반환한다.
-
-
handle을 realm에서 교차 출처 저장소 파일 시스템 내부의 disclosableEntry를 가리키는 로케이터를 가진 새
FileSystemFileHandle을 생성한 결과로 둔다 [FS]. -
global이 주어졌을 때 DOM 조작 태스크 소스에 전역 태스크를 대기열에 추가하여 result를 handle로 이행한다.
-
entry가 null이면 null을 반환한다.
-
origin이 entry의 저장 출처에 포함되어 있으면 entry를 반환한다.
참고: 원래 저장자와 해당 항목을 직접 성공적으로 작성한 모든 출처는 언제든 다시 읽을 수 있다. § 3.4.1 원래 저장자의 접근을 참조한다.
-
entry의 출처가 "
*"이면:-
entry의 해시가 PHL에 있지 않으면 null을 반환한다.
참고: 공개 해시 목록 게이트는 전역 범위 항목, 즉 그렇지 않으면 공개가 웹의 모든 출처에 도달할 수 있는 유일한 경우에만 적용된다. 아래의 목록 범위 및 동일 사이트 범위에는 적용되지 않는다. 해당 범위에서는 저장 출처가 이미 명시적이고 제한된 공개 결정을 내렸으며, 별도의 전역 보편성을 추가로 요구하면 일반적인 제한 공유(§ 3.4 리소스 가시성 상향 참조)가 흔히 독점 리소스인 항목에 대한 무관한 공개 선별에 의존하게 된다. § 7.2 교차 사이트 탐색을 참조한다.
-
entry를 반환한다.
-
-
null을 반환한다.
-
disclosable을 entry와 origin이 주어졌을 때 COS 공개 여부 결정을 실행한 결과로 둔다.
-
disclosable이 null이면 null을 반환한다.
-
origin이 disclosable의 저장 출처에 포함되어 있으면 disclosable을 반환한다.
-
사용자 에이전트가 이 요청에 GREASE 적용을 선택하면 null을 반환한다.
-
disclosable을 반환한다.
3.3. 파일 생성 및 쓰기
생성 요청
완료에 의해 생성된 FileSystemFileHandle에는
연결된 요청된 출처가 있다. 이는 핸들을 통한 쓰기가 성공적으로
완료된 뒤 검증 및 저장이
항목의 출처를
상향하려고 시도할 값이다.
CrossOriginStorageRequestFileHandleOptions
options, 전역 객체
global, Realm realm이 주어졌을 때
생성
요청을 완료하려면:
-
requestedOrigins를 options["
origins"]가 주어졌을 때 요청된 출처 정규화를 실행한 결과로 둔다. -
entry를 COS 레지스트리에서 해시가 hash와 동등한 COS 항목이 있으면 해당 항목으로, 그렇지 않으면 null로 둔다.
-
entry가 null이면:
-
handle을 realm에서 교차 출처 저장소 파일 시스템 내부의 entry를 가리키는 로케이터를 가진 새
FileSystemFileHandle을 생성한 결과로 둔다 [FS]. -
handle의 요청된 출처를 requestedOrigins로 설정한다.
참고: entry가 이미 존재했는지, 이미 "
written"인지와 관계없이 handle을 반환한다. 호출자는 여전히 handle을 통해 전체 파일 바이트를 제공해야 한다. 따라서 쓰기를 이전 존재 여부를 감지하는 데 사용할 수 없으며(§ 7.2 교차 사이트 탐색 참조), 더 허용적인 출처 값에 대한 요청을 승인하기 전에 검증할 수 있다. § 3.4 리소스 가시성 상향을 참조한다. -
global이 주어졌을 때 DOM 조작 태스크 소스에 전역 태스크를 대기열에 추가하여 result를 handle로 이행한다.
*", 출처의 목록 또는 null을 반환한다.
-
origins가 존재하지 않으면 null을 반환한다.
-
origins가 "
*"이면 "*"를 반환한다. -
list를 « »로 둔다.
-
list를 반환한다.
참고: 나중에 기존 항목으로 병합할 때만 중복을 제거하는 대신 여기에서 중복을 제거하면, 항목이 처음 생성되는 순간부터 출처에 중복이 없게 된다. 따라서 이후 만들어지는 모든 복제본에도 중복이 없다.
COS 항목을 가리키는
로케이터를 가진 핸들에서
createWritable()을
호출하여 얻은 FileSystemWritableFileStream이
닫히면 [FS],
사용자 에이전트는 해당 닫기 연산의 프로미스가 이행되기 전에 아래의 검증 및 저장 단계를 실행해야 한다.
참고: 이는 명시적인
close()
호출 또는 소스 끝에 도달하여 기본적으로 대상도 닫는 pipeTo()
호출 등 닫기가 어떤 방식으로 시작되었는지와 관계없이 적용된다. [STREAMS]는 스트림이 닫히는 시점에 두 경우를 구분하지 않으며,
이 알고리즘도 구분하지 않는다.
-
computedValue를 [WEBCRYPTO]에 따라 entry의 알고리즘이 지정하는 알고리즘을 사용해 계산한 bytes의 소문자 16진수 다이제스트로 둔다.
-
computedValue가 entry의 값과 정확히 같지 않으면:
-
닫기 연산의 프로미스를 "
DataError"DOMException으로 거부하고, entry는 수정하지 않는다. -
이 단계를 중단한다.
-
-
다음 단계를 교차 출처 저장소 큐에 대기열에 추가한다.
파일 시스템 표준
[FS]은 종속 명세가
FileSystemWritableFileStream의
닫기 단계에 쓰기별 추가 검증을 연결할 수 있는 확장 지점을 아직 정의하지 않는다. 이러한 연결 지점이 생길 때까지
이 절에서는 필요한 동작을 직접 설명한다. 향후 개정에서는 [FS]와
정식으로 통합할 것으로 예상된다.
3.4. 리소스 가시성 상향
COS 항목의 가시성은 상향할 수 있지만 하향할 수는 없다.
*", 출처의 목록 또는 null인
requestedOrigins가 주어졌을 때
리소스
가시성을 상향하려면:
-
requestedOrigins가 null이면 반환한다.
참고:
origins를 생략해도 기존 항목의 범위는 축소되지 않는다. 생략은 동일 사이트 가용성만 요청하며, 모든 항목은 이미 적어도 그만큼의 가용성을 가진다. -
entry의 출처가 "
*"이면 반환한다.참고: 이미 전역으로 사용 가능한 항목을 나중의 작성자가 제한할 수는 없다. 이 참고가 적용되고 requestedOrigins가 "
*"가 아니면 사용자 에이전트는 요청된 제한이 적용되지 않았음을 개발자에게 알리는 콘솔 경고를 기록할 것으로 예상된다. -
requestedOrigins가 "
*"이면:-
entry의 출처를 "
*"로 설정한다. -
반환한다.
-
-
entry의 출처가 null이면:
-
entry의 출처를 requestedOrigins로 설정한다.
-
반환한다.
-
-
requestedOrigins의 각 candidateOrigin에 대해 반복한다.
-
merged가 candidateOrigin을 포함하면 계속한다.
-
merged의 크기가 사용자 에이전트의 최대 출처 목록 길이와 같으면 중단한다.
참고: 나머지 candidateOrigin 값은 쓰기 자체가 이미 성공했으므로 상향을 실패시키는 대신 이 상향에서 조용히 제외된다. 다만 사용자 에이전트는 항목의 출처 목록이 최대 용량에 도달했다는 콘솔 경고를 기록할 것으로 예상된다.
-
candidateOrigin을 merged에 추가한다.
-
-
entry의 출처를 merged로 설정한다.
참고: 원래 저장자뿐 아니라 새 사이트도 항목의 출처 범위를 넓힐 수 있다. 단, 항목의 해시가 되는 바이트도 함께 제공해야 한다. 이는 의도된 동작이다. 어떤 사이트든 해당 해시에 맞는 올바른 바이트를 이미 가지고 있다면, 그 해시가 무엇을 나타내는지에 대해 구조적으로 원래 저장자와 동일한 권위를 가진다.
3.4.1. 원래 저장자의 접근
COS 항목의
쓰기를 성공적으로
완료한 출처, 즉 항목의 저장 출처에 포함된 모든
출처는 이후 언제든
requestFileHandle()을
통해
해당 항목의 핸들을 얻을 수 있다. 이는 항목의
출처 값 및
항목의 해시가 PHL에 있는지와 무관하다.
이는 출처가 자신이 저장한 항목에 항상 접근할 수 있는 Cache API의 모델을 따른다.
4. 교차 출처 저장소 파일 시스템
교차 출처 저장소 파일 시스템은 출처의 버킷 파일 시스템 또는 로컬 파일 시스템 접근 루트와 구별되는 파일 시스템 루트이다. 이 시스템의 항목은 COS 레지스트리의 COS 항목과 일대일로 대응한다.
교차 출처 저장소 파일 시스템은
[FS]의 일반적인 호출별 권한 검사
모델을 사용하지 않는다. 이 시스템에서 얻은 모든 FileSystemFileHandle은
스크립트에 반환되기 전에 이미 § 3.2 파일 읽기 또는
§ 3.3 파일 생성 및 쓰기를 통해 완전히 승인되었다. 따라서 이러한
핸들에서 getFile()
또는 createWritable()을
호출해도 추가 권한 프롬프트가 표시되지 않는다.
COS 항목
entry를 가리키는 FileSystemFileHandle은
entry의 상태가 아직
"pending"인 동안에도 존재할 수 있다.
예를 들어 생성 요청 직후, 해당 쓰기가 완료되기 전이다.
이러한 핸들에서 getFile()을
호출하면 "NotAllowedError"
DOMException으로
거부해야 한다. 이는 같은 해시에 대한 동시
requestFileHandle()
호출과 같은 이유이다(§ 3.2 파일 읽기 참조). 핸들을 요청한 호출자조차
아직 검증되지 않은 자리 표시자를 파일의 실제 내용인 것처럼 관찰할 수 없어야 한다.
entry의 상태가
"written"이 되면 이러한 핸들에서 호출한
getFile()은
내용이 entry의 바이트인
File을
반환한다. 이는 [FS]에서
이진 데이터가 entry의
바이트인
파일
항목에 이미 정의한 동작과 정확히 같다.
5. 저장소 관리
5.1. 저장소 제한
사용자 에이전트는 단일 출처가 다른 출처의 항목을 축출하기 위해 캐시를 가득 채우는 것을 방지하도록,
출처가 성공적인 쓰기를 통해
COS 레지스트리에
기여할 수 있는 총 바이트 수를 제한해야 한다. 구체적인 제한은
구현에서 정의한다. 출처의 쓰기가 제한을 초과한다면 사용자
에이전트는 해당 쓰기를 "QuotaExceededError"
DOMException으로
거부해야 하며,
콘솔에 경고를 기록하는 것이 좋다.
참고: 항목은 콘텐츠 주소 지정 가능하므로, 출처가 동일한 해시로 동일한 바이트를 반복해서 써도 최초의 성공적인 쓰기 이후에는 추가 할당량을 소비하지 않는다. § 2.2 COS 항목을 참조한다.
사용자 에이전트에는 하나의 구현에서 정의하는 최대 출처 목록 길이도 있다.
이는 하나의 출처 목록에 포함할 수 있는
출처 수의 상한인 양의 정수이다. 이 제한은 목록이 처음 제공될 때
(COS 요청 검증
참조)와
나중에 기존 항목으로 병합될 때(리소스 가시성 상향 참조)
모두 적용된다. 따라서 단일 호출이나 시간에 걸친 여러 호출의 누적 효과로 항목의
출처가 무제한 증가하지 않는다.
메모리 사용을 제한할 뿐 아니라, 출처 목록이 "*"의
선언되지 않은 대용물로 사용되는 것도 방지한다. § 7.2 교차 사이트 탐색을
참조한다.
두 호출은 연산의 매우 다른 시점에 발생하므로, 이 제한을 초과한 경우 각 위치에서 다르게 처리한다.
-
COS 요청 검증에서는 파일을 가져오거나, 해시하거나, 쓰기 전에 제한을 검사한다. 제한을 초과한 호출자는 즉시 "
TypeError"를 받고 그 밖의 동작은 발생하지 않는다. 이는 잘못된 다른 모든origins값과 동일한 처리이다. -
리소스 가시성 상향에서는 여러 개의 독립적인 쓰기 호출에서, 장기간에 걸쳐 서로 관련 없는 출처들이 요청한 출처의 누적 효과로만 제한에 도달할 수 있다. 또한 이 검사는 해당 호출의 바이트가 이미 해시되고, 검증되고, 영구적으로 저장된 이후에만 수행된다. 이 시점에서 쓰기를 거부하면 무관한 장부 관리 제한 때문에 성공적으로 검증된, 잠재적으로 매우 큰 쓰기를 폐기하게 되며, 이를 단일 호출자의 실수로 돌릴 수도 없다. 따라서 쓰기는 성공한 상태로 두고 용량을 초과하는 출처만 출처에서 제외하며 콘솔 경고를 기록한다. 이는 기존의 더 허용적인 범위에서 더 제한적인 범위로의 요청 처리와 같다. 완전히 승인할 수 없는 출처 요청은 이를 전달한 쓰기를 실패시키는 대신 조용히 상한이 적용된다. 이 명세의 다른 곳에서 사용되는 § 7.3 가용성 게이팅과 마찬가지로, 호출자는 요청한 출처가 실제로 추가되었는지 나중에 신뢰성 있게 확인할 수 없다. 해당 출처에서 이후
requestFileHandle()을 호출해도 출처가 추가되었음에도 실패할 수 있다. 예를 들어 GREASE 적용 때문이다. 따라서 결과를 어느 쪽으로든 확인으로 해석해서는 안 된다.
5.2. 축출
이 절은 비규범적이다.
저장 공간이 부족하면 사용자 에이전트는 COS 레지스트리에서 항목을 축출할 수 있다. 예를 들어 각 항목에 가장 최근 접근한 저장 출처 전체를 기준으로 가장 오래 사용되지 않은 항목을 우선하는 정책을 사용할 수 있다. 사용자 에이전트는 사용자가 저장된 파일, 각 파일에 접근한 출처를 확인하고, 항목을 수동으로 삭제하거나 모든 교차 출처 저장소 데이터를 지울 수 있는 설정 UI를 제공할 것으로 예상된다.
사용자가 출처의 사이트 데이터를 지우면 사용자 에이전트는 해당 출처가 포함된 모든 저장 출처 집합에서 해당 출처를 제거하는 것이 좋다. 제거한 뒤 COS 항목의 저장 출처가 비어 있으면 사용자 에이전트는 해당 항목의 삭제를 고려할 수 있다.
5.3. 수동으로 추가된 항목
이 절은 비규범적이다.
위에서 설명한 설정 UI를 통해 사용자는 디스크에 이미 보유한 파일을 교차 출처 저장소에 직접 추가할 수 있다.
예를 들어 웹사이트와 무관하게 다운로드한 AI 모델이며, 스크립트에서 requestFileHandle()을
호출하지 않아도 된다. 이러한 항목에는 쓰기를 귀속할 요청 출처가 없으므로, 명령형 API만으로는 답할 수 없는 두 가지 문제가 생긴다.
-
§ 3.4.1 원래 저장자의 접근에서 말하는 원래 저장자는 누구인가? 아무도 아니다. 항목의 저장 출처는 쓰기를 수행한 출처를 포함하는 대신 비어 있는 상태로 시작한다. 따라서 어떤 출처도 모든 요청 출처에 적용되는 일반적인 가용성 게이팅 및 출처 검사에서 면제되지 않는다. 실제로 바이트를 작성한 출처가 없으므로 이것이 올바른 결과이다.
-
출처는
origins를 생략한 일반 쓰기처럼 동일 사이트 전용을 기본값으로 해야 하는가? 그렇지 않다. "동일 사이트"는 요청 출처와의 관계에서만 의미가 있으며, 수동 추가에는 요청 출처가 없으므로 "동일 사이트"가 의미할 사이트도 없다. 사용자 에이전트는 이러한 항목의 출처를 대신 "*"로 기본 설정할 것으로 예상된다. 사용자가 아직 방문하지 않은 사이트가 사용자의 디스크에 이미 있는 파일을 재사용하게 한다는 수동 파일 추가의 목적은 다른 출처가 실제로 해당 파일을 발견할 수 있어야 달성되기 때문이다. 사용자 에이전트의 설정 UI에서는 사용자가 더 좁은 범위를 선택할 수 있게 할 수도 있다.
이 방식으로 추가된 뒤 상태가
"written"인 항목은 그 밖의 측면에서
웹사이트가 requestFileHandle()을
통해 작성한 항목과 구별할 수 없다. 동일한 가용성 게이팅 및
가시성
상향 규칙이 동일한 출처
값을 가진 다른 모든 항목과 정확히 같은 방식으로 적용된다.
항목이 "*" 범위가 되면 PHL에
있는지도 검사한다. 이는 수동 추가의 기본값이지만 유일한 결과는 아니다.
6. 권한 정책 통합
이 명세는 문자열 "cross-origin-storage"로 식별되는
정책 제어 기능
[permissions-policy]을 정의한다.
기본 허용 목록은 self이다.
이 기능을 사용하도록 허용되지 않은 Document에서는 해당 Document 또는 소유자가 해당 Document인 워커에서
이루어진 모든
requestFileHandle()
호출이 해시 검증, 레지스트리 조회 또는 쓰기를 수행하기 전에 "NotAllowedError"
DOMException으로
거부된다.
7. 개인정보 보호 및 보안 고려사항
이 절은 RFC 2119 키워드를 사용하는 부분을 제외하면 비규범적이다. 저장소의 보안 및 개인정보 보호 설문도 참조한다.
7.1. 리소스 무결성
모든 COS 항목은
암호학적 해시를 키로 사용하며 해당 해시를 기준으로 바이트를 검증한다
(§ 3.3 파일 생성 및 쓰기 참조). 따라서 사이트는
requestFileHandle()을
통해 얻은 파일의 바이트가 hash를 직접 가져왔을 때 얻었을 바이트와 정확히 같음을 확신할 수 있다.
개발자는 교차 출처 저장소의 내용을 열거하거나 해시를 이미 알지 못하는 파일에 접근할 수 없다.
COS 해시는 비밀이 아니다. 이는 파일을 이미 가진 누구나 간단히 계산할 수 있는 콘텐츠 식별자이며, 이 명세가 대상으로 하는 널리 배포되는 종류의 리소스에서는 일반적으로 공개된 정보이다. 예를 들어 모델이나 라이브러리의 릴리스와 함께 게시된다. 따라서 해시를 알면 항목을 조회할 수 있지만, 기능 URL이나 소지자 토큰과 달리 해시 자체는 접근 권한을 부여하지 않는다. 조회 성공 여부는 해시가 공개되지 않은 상태로 유지되었는지가 아니라 전적으로 출처와 § 7.3 가용성 게이팅에 의해 결정된다. 개발자는 공개되지 않은 해시를 접근 제어 수단으로 취급해서는 안 된다. 특정 파일에 관심 있는 공격자는 해시를 추측할 필요 없이 파일 자체를 얻기만 하면 된다(§ 7.2 교차 사이트 탐색 참조).
7.2. 교차 사이트 탐색
리소스를 사용하는 사이트가 소수에 불과하면, 공격자는 해당 리소스가 교차 출처 저장소에 존재함을 알아내어
사용자가 해당 사이트 중 하나를 방문했을 가능성이 높다고 추론할 수 있다.
requestFileHandle()이
존재 여부를 알아내는 메커니즘이므로 각 호출은 사실상 탐색이다. 이 명세의 두 독립적인 메커니즘은 탐색으로
알아낼 수 있는 정보를 제한한다.
-
출처 (§ 3.4 리소스 가시성 상향 참조)를 사용하면 저장 출처가 공개 범위를 선택한 출처 집합으로 제한할 수 있다. 따라서 독점적이거나 인기가 낮은 리소스를 전역에서 탐색할 수 있게 할 필요가 없다.
-
§ 7.3 가용성 게이팅은 해시가 PHL에 있지 않으면 "
*" 범위 리소스를 저장 출처 외부의 요청 출처에 공개하지 않는다. 따라서origins: "*"로 저장한 리소스를 웹의 모든 출처에서 자동으로 탐색할 수 있는 것은 아니다. 이 게이트는 "*" 범위 항목에만 적용된다. 목록 범위 및 동일 사이트 범위 항목에서는 저장 출처가 공개 범위를 이미 명시적으로 제한했으므로 첫 번째 항목의 제한이 유일한 게이트이다.
첫 번째 항목은 "선택한 출처 집합"이 웹 전체보다 의미 있게 작게 유지되는 경우에만 성립한다.
origins의
형태는 호출자가 매우 많은 출처를 열거하는 것을 막지 않는다. 예를 들어 공개 상위 사이트 순위에서 만든
목록은 "*"에만 요구되는 의도적이고 명시적인 선택을 우회하면서 기능적으로 전역 공개와 비슷해진다.
최대 출처
목록
길이(§ 5.1 저장소 제한 참조)는 이를 제한한다.
진정한 다중 속성 사용 사례, 즉 공통 관리 아래의 소수 관련 출처에는 충분하지만 "모든 출처"를 의미 있게
근사하기에는 턱없이 작은 제한을 사용하면 제한 출처 형태의 출처를 "*"의
선언되지 않은 대용물로 사용할 수 없다.
사용자 에이전트는 단일 출처에서 반복되는
requestFileHandle()
호출의 비율을 제한하거나 다른 방식으로 조절하는 것이 좋다. 또한 탐색된 해시가
PHL에 있는지와 관계없이
온디바이스 휴리스틱을 적용하여, 예를 들어 사용자별로 생성된 것으로 보이는 해시 요청 패턴을 감지해
탐색 시도를 식별하고 차단할 수 있다.
7.3. 가용성 게이팅
저장
출처 외부의 출처에서 수행한 requestFileHandle()
읽기의 성공 여부는 항상 요청 출처가 항목을 읽도록 허용되는지에 달려 있으며, 이는
출처에 의해 관리된다.
"*" 범위 항목에는
독립적인 두 번째 문제도 적용된다. 사용자 에이전트가 항목의 존재 자체를 공개할 의향이 있는지이며,
이는 PHL
멤버십과 GREASE 적용에 의해 관리된다.
이러한 항목에는 두 조건이 모두 성립해야 한다. 목록 범위 또는 동일 사이트 범위 항목에는 첫 번째 조건만
적용되지만, GREASE 적용으로 출처가 허용할 공개도 억제할 수 있다.
규범적 알고리즘은 § 3.2 파일 읽기를 참조한다. 따라서 "NotFoundError"는
리소스가 존재하지 않는다는 증거가 아니다. 리소스가 존재하지 않거나, 요청 출처가 범위 밖이거나,
"*" 범위 리소스의 해시가 아직 PHL에 없거나 영원히 없을 수 있으며, GREASE 적용이 실제 성공을
억제했을 수도 있다. 개발자는 "NotFoundError"를
"네트워크로 대체한다"보다 구체적인 의미로 취급해서는 안 된다.
7.4. GREASE 적용
사용자 에이전트는 GREASE 적용(무작위 확장을 생성하고 확장 가능성을 유지하기)을 수행할 수 있다. 즉, § 7.3 가용성 게이팅에 따라 공개가 허용되는 경우에도 공개 가능한 항목이 존재하지 않는 것처럼 가끔 응답할 수 있다. 이는 사이트가 실제 부재와 개인정보 보호를 위한 거짓 부정을 구분하기 어렵게 만드는 노이즈를 추가하며, UA 클라이언트 힌트가 사용하는 기법과 유사하다.
GREASE 적용을 수행하는 사용자 에이전트는 해당 항목의 크기에 비례하는 판단을 내려야 한다. 네트워크에서 다시 가져오는 비용이 낮은 작은 항목에서는 가끔 발생하는 거짓 부정이 합리적인 개인정보 보호 절충안이다. 그러나 사용자 에이전트는 거짓 재다운로드의 비용이 그에 따른 개인정보 보호 이점과 비교해 명백히 과도한 크기의 항목에는 GREASE를 적용해서는 안 된다. 예를 들어 기가바이트 규모의 AI 모델 가중치가 해당한다. 이러한 항목에서 거짓 부정은 저렴한 재다운로드가 아니라 전체 파일의 관찰 가능하고 비용이 큰 재다운로드를 강제한다.
7.5. 핑거프린팅
공격자가 교차 출처 저장소를 탐색하여 추출할 수 있는 정보는 탐색 대상 리소스의 인기도에 따라 제한된다. 일반적인 AI 모델이나 널리 사용되는 JavaScript 라이브러리와 같이 매우 인기 있는 리소스를 사용자가 가지고 있음을 알아내도, 사용자가 해당 리소스를 사용하는 수많은 사이트 중 하나를 방문했다는 사실만 드러난다. 드물거나 고유한 리소스를 사용자가 가지고 있음을 알아내는 것은 훨씬 더 많은 정보를 제공한다. 사용자 에이전트는 해시가 사용자별로 의도적으로 고유하게 보이는 리소스를 감지하도록 온디바이스 휴리스틱을 적용할 것으로 예상된다. 예를 들어 특정 해시를 오직 하나의 사이트에서만 작성했거나 비정상적으로 자주 요청하는 경우이며, 명목상의 PHL 상태와 관계없이 이러한 패턴을 탐색 시도로 취급한다.
8. 다른 명세와의 통합
이 절은 비규범적이다.
여기에서 정의한 COS 레지스트리는
requestFileHandle()을
직접 통하지 않고도 세 호스트 언어에서 선언적으로 접근할 수 있다. 각 통합은 이 문서가 아니라 자체 호스트 언어의
명세에서 정의한다. 이 명세는 해당 통합이 기반으로 삼을 공유 개념인 COS
해시, COS 항목, 가용성 게이팅,
공개 해시 목록만 정의한다.
-
HTML: 이미
integrity를 가진link및script요소의crossoriginstorage속성이다 [SRI]. WHATWG HTML 표준에 제안할 예정이다. -
JavaScript: 가져오기 속성 제안을 기반으로 하며
integrity와 함께 사용할 수 있는 호스트 정의crossOriginStorage가져오기 속성이다. WHATWG HTML 표준에 제안할 예정이다. -
CSS:
integrity()와 함께 사용할 수 있는cross-origin-storage()<request-url-modifier>이다. w3c/csswg-drafts#14056에서 CSS 워킹 그룹에 제안되었다.
설명 목적으로만, 다음은 동일한 전역 공유 리소스를 세 가지 형식으로 교차 출처 저장소에 사용하도록 선택하는 예이다.
< script src = "popular-library.js" integrity = "sha256-abc123..." crossoriginstorage = "*" ></ script >
import datafrom "popular-resource.ext" with { integrity: "sha256-abc123..." , crossOriginStorage: "*" , };
@font-face { font-family : "Popular Font" ; src : url ( "popular-font.woff2" integrity("sha256-abc123..." ) cross-origin-storage ( *)); }
이 코드 조각은 설명용일 뿐이다. 이 구문은 이 명세에서 정의하지 않으며,
제한된 비-"*" 출처 값을 표기하는 방법을 포함한 각 형식의 권위 있는 문법은 이 문서가 아니라
자체 호스트 언어 명세에 속한다.
세 형식 모두 네트워크 가져오기로 대체하기 전에 일치하며 공개 가능한 항목이 있는지
COS 레지스트리를 먼저 확인하고,
성공적으로 가져와 무결성이 검증된 리소스를 다른 출처에서 재사용하도록 COS 레지스트리에 저장하는 처리 모델을
공유할 것으로 예상된다. 이는 requestFileHandle()과
정확히 같다. 이러한 통합에 관한 논의는 이 저장소의 이슈 추적기가 아니라 해당 통합을 포함할 호스트 언어
명세의 추적기에서 이루어져야 한다.
감사의 말
귀중한 피드백을 제공한 Tab Atkins-Bittner, Yash Raj Bharti 및 Joshua Lochner와, 귀중한 영감과 아이디어를 제공한 Kenji Baheux 및 Kevin Moore에게 깊이 감사한다.
이 명세에는 파일 시스템을 본뜬 자료가 포함되어 있으며, 해당 자료는 W3C 소프트웨어 및 문서 라이선스에 따라 제공된다.