교차 출처 저장소

커뮤니티 그룹 보고서 초안,

이 버전:
https://wicg.github.io/cross-origin-storage/
이슈 추적:
GitHub
명세 내 인라인 표시
편집자:
(Google)
(Thinktecture AG)
(Google)
참여:
GitHub WICG/cross-origin-storage (새 이슈, 미해결 이슈)
커밋:
GitHub index.bs 커밋

초록

교차 출처 저장소(Cross-Origin Storage, COS)는 웹 애플리케이션이 AI 모델, WebAssembly 모듈, 널리 사용되는 JavaScript 라이브러리 등의 대용량 파일을 서로 다른 출처 간에 저장하고 검색할 수 있도록 하는 콘텐츠 주소 지정 가능 캐시이다. 파일은 URL이 아니라 암호학적 해시로 식별되므로, 한 출처에서 한 번 가져온 바이트 단위로 동일한 리소스를 사용자 에이전트가 허용하는 다른 모든 출처에서 두 번째 다운로드 없이 재사용할 수 있다. 캐시의 존재 여부를 사용자가 방문한 사이트를 추론하는 데 이용하지 못하도록, 파일의 교차 출처 공개는 k-익명성 방식의 인기도 기준을 충족하는 해시로 제한된다.

이 문서의 상태

이 명세는 웹 플랫폼 인큐베이터 커뮤니티 그룹에서 발행했다. 이 문서는 W3C 표준이 아니며 W3C 표준화 절차에도 포함되지 않는다. 다음 사항에 유의한다. W3C 커뮤니티 기여자 라이선스 계약 (CLA)에는 제한된 참여 거부 조항이 있으며 그 밖의 조건도 적용된다. W3C 커뮤니티 및 비즈니스 그룹에 대해 자세히 알아본다.

1. 소개

이 절은 비규범적입니다.

스토리지는 일반적으로 사용자의 보안과 프라이버시를 보호하기 위해 오리진별로 분할됩니다. 이는 적절한 기본 설정이지만, 어떤 사이트에서 요청하더라도 바이트 단위로 동일한 파일인 매우 크고 매우 인기 있으며 공개적으로 배포되는 리소스(AI 모델, WebAssembly 모듈, JavaScript 라이브러리, 게임 엔진 및 대형 웹 폰트)의 좁은 범주에는 적합하지 않습니다. 서로 관련 없는 두 오리진이 동일한 8GB 모델에 각각 의존하는 경우, 오리진별로 분할된 스토리지는 사용자가 해당 모델을 두 번 다운로드하고 유지하도록 강제하며, 이는 사용자의 대역폭, 스토리지 및 배터리와 전체 네트워크 측면에서 낭비입니다.

Cross-Origin Storage(COS)는 URL이 아니라 암호학적 해시를 키로 사용하는 콘텐츠 주소 지정 가능 캐시로, 사용자 에이전트가 이러한 리소스의 저장된 단일 사본을 사용에 동의한 여러 출처 간에 공유할 수 있게 합니다. COS에 리소스를 저장하는 것은 항상 저장 출처가 명시적으로 동의하여 수행하는 작업이며, 사용자 에이전트는 원래 해당 리소스를 읽을 수 있도록 허용되는 출처에 대해서도 리소스의 존재 확인을 제공하지 않을 수 있습니다. § 8 개인정보 보호 및 보안 고려사항을 참조하십시오.

이 명세의 진입점은 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') {
    // Cross-Origin Storage에 (공개 가능한 상태로) 존재하지 않으므로, 대신 네트워크에서 가져옵니다.
  }
}

이 명세는 전용 파일 시스템을 대상으로 File System Standard [FS]에서 가져온 FileSystemFileHandle, FileSystemWritableFileStream 및 관련 인프라를 재사용합니다. 이 전용 파일 시스템은 오리진 간에 공유되며, 어떠한 오리진의 비공개 또는 사용자 표시용 파일 시스템과도 분리됩니다.

이 명세는 명령형 JavaScript API와 호스트 통합이 기반으로 구축하는 공유 스토어 단계를 정의합니다. 관련 제안은 동일한 기본 캐시를 다른 호스트 명세에 통합합니다. 여기에는 linkscript의 HTML crossoriginstorage 속성, crossOriginStorage JavaScript import 속성, CSS cross-origin-storage() <request-url-modifier>, 그리고 fetch()crossOriginStorage RequestInit 옵션이 포함됩니다. 각각은 자체 호스트 명세에서 정의되며, 자세한 내용은 § 9 다른 명세와의 통합을 참조하십시오.

2. 개념

2.1. 해시

A COS hash는 다음 items를 가지는 struct입니다:

algorithm

문자열이며, [WEBCRYPTO]에서 인식되는 해시 알고리즘의 이름을 지정합니다. 예를 들어 "SHA-256"입니다.

value

문자열이며, algorithm이 생성한 다이제스트의 소문자 16진수 인코딩입니다. "SHA-256"의 경우 길이는 64자입니다.

algorithm 사전 멤버는 일반 DOMString 타입으로 지정됩니다. 하지만 해당 값 공간은 정확히 [WEBCRYPTO]의 해시 알고리즘이 허용하는 이름 집합입니다. HashAlgorithmIdentifier(object or DOMString)이며, [WEBCRYPTO]에서 object 분기를 Algorithm 형태의 사전으로 정규화하면, 호출자는 추가 매개변수가 필요한 알고리즘에 추가 매개변수를 전달할 수 있습니다(예: {name: "HMAC", hash: "SHA-256"}). 해시 알고리즘은 이러한 매개변수를 사용하지 않으며, algorithm콘텐츠 주소 지정 가능 키의 일부로 저장되고 비교되며 왕복 처리되고, 이 명세의 예제에서 사용하는 모든 경우는 단순 문자열입니다. 여기에서 임의의 객체를 허용하는 것은 기능을 추가하지 않으면서 동등성과 직렬화를 불필요하게 복잡하게 만들 뿐입니다. 따라서 DOMString은 이 필드에 대해 더 좁고 더 올바른 타입입니다.

COS 해시 값은 동등합니다. 이는 해당 algorithm 값이 ASCII 대소문자를 구분하지 않는 일치이고, 해당 value 값이 정확히 동일한 경우입니다.

참고: value는 이미 규범적으로 소문자입니다(위 참조). 따라서 이를 비교하는 것은 단순한 문자열 비교입니다. algorithm에는 규범적인 대소문자가 없으므로, ASCII 대소문자를 구분하지 않는 방식으로 비교합니다.

콘텐츠 주소 지정 가능 스토어는 항목의 키가 동등성에 의해 결정되는 스토어입니다. 즉, 동일한 바이트와 동일한 해시 알고리즘을 가진 두 파일은 이를 저장한 오리진의 수나 가져온 URL의 수와 관계없이 동일한 항목입니다.

2.2. COS 항목

각 사용자 에이전트에는 하나의 COS 레지스트리가 있으며, 이는 COS 해시 값에서 COS 항목 구조체로의 이며, Cross-Origin Storage를 사용하는 모든 출처에서 공유됩니다. COS 항목에는 다음 항목이 있습니다.

hash

COS 해시입니다.

bytes

null 또는 바이트 시퀀스이며, hashalgorithm에 따른 다이제스트가 hashvalue와 같은 값입니다. 작성자가 검증 및 저장을 완료할 때까지 null입니다.

state

"pending" 또는 "written" 중 하나입니다. 항목은 처음에는 "pending" 상태이며, bytes가 처음 설정되는 시점에 정확히 한 번 "written" 상태가 됩니다.

pending writer count

0부터 시작하는 음이 아닌 정수이며, 아직 완료되지 않은 작성자를 계산합니다: FileSystemFileHandle 핸들은 생성 요청 완료에 의해 반환되며, 해당 닫기 쓰기가 아직 완료되지 않았습니다. 이는 검증 및 저장에서 실패한 쓰기를 안전하게 정리할 수 있는지 결정할 때만 사용됩니다. 자세한 내용은 § 3.3 파일 생성 및 쓰기를 참조하십시오.

origins

목록이며, 오리진 목록입니다. 공개 해시 목록과 독립적으로 명시적인 크로스 오리진 읽기 접근 권한이 부여된 오리진을 포함합니다. 처음에는 비어 있으며, 오직 증가하기만 합니다. 이는 누가 항목을 읽을 수 있는지를 결정하는 세 가지 독립적이고 추가적인 권한 부여 중 하나이며, 나머지 두 가지는 해당 항목의 storing origins(항상 읽을 수 있으며, 이들과 same site인 오리진도 포함)와 globally disclosable입니다.

globally disclosable

불리언이며, 처음에는 false입니다. 항목이 전역("*") 사용 가능 요청과 함께 작성되었는지를 기록합니다. true인 경우, 요청이 § 8.3 가용성 제어를 통과한 모든 오리진에서 해당 항목을 읽을 수 있습니다. 즉, 해당 hashPHL에 있으며 GREASE 처리가 억제하지 않는 경우입니다. 한 번 설정되면 계속 true입니다.

참고: 이는 origins와 별도의 항목입니다. 따라서 이후의 전역 사용 가능 요청은 기존의 명시적인 origins 목록 위에 "*" 권한을 추가합니다. 두 항목을 하나의 필드로 합치면 바이트를 제공한 작성자가 목록 범위 항목을 "*" 범위 항목으로 변경할 수 있습니다. § 8.3 가용성 제어는 "*" 권한에만 적용되므로, 이전에 목록에서 항목을 읽을 수 있었던 오리진은 이후 hashPHL에 없을 때마다 "NotFoundError"를 받게 됩니다. 권한을 독립적으로 유지하면 모든 가시성 변경은 엄격하게 추가 방식이 되며, 이는 업그레이드는 가능하지만 다운그레이드는 불가능해야 한다는 요구 사항에 부합합니다.

storing origins

순서가 있는 집합이며, 각각 이 항목의 바이트를 작성하는 작업을 최소 한 번 성공적으로 완료한 오리진의 집합입니다. 페이지 로드 간에 유지되며 시간이 지남에 따라 증가합니다. § 5.2 제거에 설명된 경우를 제외하고는 절대 감소하지 않습니다. storing origins에 포함된 오리진은 requestFileHandle()을 통해 항상 해당 항목의 핸들을 얻을 수 있으며, 이는 origins 또는 항목의 hash공개 해시 목록(PHL)에 있는지 여부와 관계없습니다. § 3.5.1 원래 저장자 접근을 참조하십시오.

사용자 에이전트에는 연관된 Cross-Origin Storage 큐가 있으며, 이는 새 병렬 큐를 시작한 결과입니다. COS 레지스트리에 대한 모든 작업은 이 큐에 대기열에 추가되어야 하며, 그러면 해당 작업은 대기열에 추가된 순서대로 실행되고 서로 끼어들지 않습니다.

2.3. 공개 해시 목록

Cross-Origin Storage에 해시가 존재하는지 확인하는 것 자체가 사용자의 브라우징 기록에 관한 정보를 유출할 수 있습니다( § 8.2 크로스 사이트 프로빙 참조). 이는 특히 전역 권한 부여에 대한 위험입니다. 항목의 명시적인 origins 목록과 모든 항목이 가지는 동일 사이트 기준은 이미 저장 오리진의 명시적인 선택에 의해 공개 범위가 제한되어 있습니다. 반면 항목을 globally disclosable로 만들면 웹상의 모든 오리진에 잠재적으로 노출됩니다. 이 특정 위험을 제한하기 위해 globally disclosable 리소스는 해당 권한 부여를 통해 storing origins 외부의 오리진에 공개되려면 해시가 추가적이고 독립적인 게이트를 통과해야 합니다. 즉, Public Hash List (PHL)에 포함되어야 합니다. PHL은 벤더 중립적인 구현 정의 COS 해시 값 허용 목록입니다. 해시는 k-익명성 방식의 인기 기준(예: 독립적인 최소 수 이상의 오리진에서 바이트 단위로 동일하게 나타나는 경우)을 통과한 후에만 Public Hash List에 등록되므로, 공유 캐시에 해당 해시가 존재하는지 확인하는 것이 특정 개인 사용자에 대한 정보를 제공하지 않도록 합니다.

COS 해시 hashhash가 사용자의 사용자 에이전트의 현재 Public Hash List 스냅샷의 항목과 동등한 경우 Public Hash List에 있음입니다.

Public Hash List의 검색 프로토콜, 업데이트 주기, 데이터 형식, 인기 임계값 및 거버넌스는 이 명세의 보조 산출물로서 자세히 설계되었습니다. 이는 [URL] Standard의 보조 데이터 파일인 공개 접미사 목록(public suffix list)과 같은 방식입니다. 자세한 내용은 이 저장소의 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;

NavigatorWorkerNavigator 객체에는 연관된 CrossOriginStorageManager 객체가 있습니다. crossOriginStorage getter 단계는 this에 연관된 CrossOriginStorageManager를 반환하는 것입니다.

CrossOriginStorageManager 객체에는 연관된 출처가 있으며, 객체가 생성될 때 this관련 설정 객체출처로 설정됩니다.

참고: 스크립트 자체에 관한 어떤 내용과도 독립적으로 관련 설정 객체에서 오리진을 가져오는 것은 워커와 관련하여 설명할 가치가 있는 결과를 가져옵니다. blob: URL에서 생성된 워커는 이를 생성한 컨텍스트의 origin을 가지므로, 해당 오리진의 Cross-Origin Storage 보기를 정확히 공유합니다. 즉, 이러한 워커가 작성한 내용은 생성한 페이지가 다시 읽을 수 있고, 페이지가 저장한 내용은 워커가 읽을 수 있습니다. blob: URL 자체는 고유한 오리진이 아니며, 이를 폐기하더라도 워커가 해당 보기를 분리하지 않습니다. data: URL에서 생성된 워커는 opaque origin을 가집니다. 이 명세는 현재 호출하는 오리진이 opaque인 경우 requestFileHandle()이 수행하는 동작을 정의하지 않습니다. opaque origin 규칙은 COS 요청 검증에서 호출자가 지정하는 오리진에만 적용됩니다. opaque origin은 storing origins 또는 same site 비교의 기준으로 사용할 안정적인 식별자가 없으므로, 해당 오리진에 부여할 의미 있는 권한도 없습니다.

3.1. requestFileHandle() 메서드

handle = await navigator . crossOriginStorage . requestFileHandle(hash)

hash로 식별되는 파일이 Cross-Origin Storage에 존재하며 호출 출처에 공개할 수 있는 경우 해당 파일의 핸들을 반환합니다. 그렇지 않으면 "NotFoundError" DOMException으로 거부됩니다. "NotFoundError"는 파일이 Cross-Origin Storage에 물리적으로 존재하지 않는다는 것을 증명하지 않습니다. § 8.3 가용성 게이팅을 참조하십시오. 호출자는 이를 "대신 네트워크에서 가져오십시오."로 취급할 수 있습니다.

handle = await navigator . crossOriginStorage . requestFileHandle(hash, { create: true })

hash로 식별되는 파일을 Cross-Origin Storage에 쓰는 데 사용할 수 있는 핸들을 반환하며, 아직 항목이 존재하지 않으면 새 항목을 생성하고, 기본적으로 동일 사이트 출처로 제한합니다. 호출자는 항목이 이미 존재했는지 여부와 관계없이 핸들의 createWritable() 메서드를 통해 완전한 파일 내용을 작성해야 합니다. 사용자 에이전트는 그 시점에 작성된 바이트의 해시가 hash와 일치하는지 검증하며, 그렇지 않으면 "DataError" DOMException으로 거부합니다. 이 요구사항은 출처가 생성 요청을 사용하여 hash가 이미 존재했는지를 알아내는 오라클로 사용하는 것을 방지합니다.

handle = await navigator . crossOriginStorage . requestFileHandle(hash, { create: true, origins: "*" })

위와 같으며, 추가로 작성이 완료되면 hash에 대한 요청이 § 8.3 가용성 게이팅을 통과하는 모든 출처에 항목을 공개할 수 있게 합니다.

handle = await navigator . crossOriginStorage . requestFileHandle(hash, { create: true, origins: ["https://a.example", "https://b.example"] })

위와 같으며, 공개를 정확히 나열된 출처로 제한합니다(호출 출처 및 이미 저장 출처에 있는 모든 출처에 추가하여).

requestFileHandle(hash, options) 메서드의 단계는 다음과 같습니다.
  1. result새 promise로 둡니다.

  2. realmthis관련 Realm으로 둡니다.

  3. globalthis관련 전역 객체로 둡니다.

  4. originthis에 연관된 출처로 둡니다.

  5. global이 주어졌을 때 Cross-Origin Storage 권한 확인을 실행한 결과가 false이면 다음을 수행합니다.

    1. global이 주어졌을 때 DOM 조작 작업 소스에서 전역 작업을 대기열에 추가하여 result를 "NotAllowedError" DOMException으로 거부합니다.

    2. result를 반환합니다.

  6. validationFailurehashoptions이 주어졌을 때 COS 요청 검증을 실행한 결과로 둡니다.

  7. validationFailure가 null이 아니면 다음을 수행합니다.

    1. global이 주어졌을 때 DOM 조작 작업 소스에서 전역 작업을 대기열에 추가하여 resultvalidationFailure거부합니다.

    2. result를 반환합니다.

  8. 다음 단계를 Cross-Origin Storage 큐대기열에 추가합니다.

    1. options["create"]가 true이면 다음을 수행합니다.

      1. result, hash, options, global, 그리고 realm이 주어졌을 때 생성 요청 완료를 실행합니다.

    2. 그렇지 않으면 다음을 수행합니다.

      1. result, hash, origin, global, 그리고 realm이 주어졌을 때 읽기 요청 완료를 실행합니다.

  9. result를 반환합니다.

CrossOriginStorageRequestFileHandleHash hashCrossOriginStorageRequestFileHandleOptions options이 주어졌을 때 COS 요청을 검증하려면, null 또는 TypeError를 반환합니다.
  1. hash["algorithm"]이 [WEBCRYPTO]에서 인식하는 해시 알고리즘 이름이 아니면 새 TypeError를 반환합니다.

  2. hash["value"]가 hash["algorithm"]이 "SHA-256"과 ASCII 대소문자를 구분하지 않고 일치할 때 정규 표현식 /^[0-9a-f]{64}$/과 일치하지 않으면 새 TypeError를 반환합니다.

    참고: 향후 해시 알고리즘은 다른 예상 다이제스트 길이를 정의할 수 있습니다. 이 명세는 예제 전반의 사용과 일치하도록 "SHA-256"만 규범적으로 제한합니다.

  3. options["origins"]가 존재하고 "*"가 아니면 다음을 수행합니다.

    1. candidatesoptions["origins"]로 두며, 단일 문자열은 하나의 항목을 가진 목록으로 취급합니다.

    2. candidates크기가 사용자 에이전트의 최대 출처 목록 길이보다 크면 새 TypeError를 반환합니다.

    3. candidates의 각 candidate에 대해 다음을 수행합니다.

      1. candidate에 대해 기본 URL 파서를 실행한 결과가 실패이거나, 파싱된 URL의 출처불투명 출처이면 새 TypeError를 반환합니다.

  4. null을 반환합니다.

3.2. 파일 읽기

promise result, COS 해시 hash, 출처 origin, 전역 객체 global, 그리고 Realm realm이 주어졌을 때 읽기 요청을 완료하려면 다음을 수행합니다.
  1. entryCOS 레지스트리에서 hashhash동일한 COS 항목이 있으면 해당 항목으로, 그렇지 않으면 null로 둡니다.

  2. entry가 null이 아니고 entrystate가 "pending"이면 다음을 수행합니다.

    1. global이 주어졌을 때 DOM 조작 작업 소스에서 전역 작업을 대기열에 추가하여 result를 "NotAllowedError" DOMException으로 거부합니다.

    2. 반환합니다.

    참고: 쓰기가 진행 중인 해시는 의도적으로 존재하지 않는 해시처럼 동작하지 않습니다. 이는 호출자가 진행 중인 쓰기를 진짜 캐시 미스로 잘못 판단하여, 오직 해당 파일을 쓰기 위한 목적으로 매우 큰 파일을 중복하여 동시에 다운로드하기 시작하지 않도록 하기 위한 것입니다. § 3.3 파일 생성 및 쓰기를 참조하십시오.

  3. disclosableEntryentryorigin이 주어졌을 때 가용성 게이팅 적용을 실행한 결과로 둡니다.

  4. disclosableEntry가 null이면 다음을 수행합니다.

    1. global이 주어졌을 때 DOM 조작 작업 소스에서 전역 작업을 대기열에 추가하여 result를 "NotFoundError" DOMException으로 거부합니다.

    2. 반환합니다.

  5. handlerealm에서 Cross-Origin Storage 파일 시스템 내의 disclosableEntry를 가리키는 locator를 가진 새 FileSystemFileHandle생성한 결과로 둡니다 [FS].

  6. handleCOS 출처origin으로 설정합니다.

  7. handle읽기 가능을 true로 설정합니다.

    참고: 이 핸들은 이미 가용성 게이팅 적용을 통과했으므로 호출 출처는 해당 항목의 바이트를 받을 권한이 있습니다.

  8. global이 주어졌을 때 DOM 조작 작업 소스에서 전역 작업을 대기열에 추가하여 resulthandle이행합니다.

COS 공개 여부 결정COS 항목 또는 null entryorigin origin이 주어졌을 때 COS 항목 또는 null을 반환합니다:

  1. entry가 null이면 null을 반환합니다.

  2. 단언: entrystate는 "written"입니다.

  3. originentrystoring origins에 포함되어 있으면 entry를 반환합니다.

    참고: 원래 저장자와 해당 항목을 직접 성공적으로 작성한 모든 오리진은 항상 이를 다시 읽을 수 있습니다. § 3.5.1 원래 저장자 접근을 참조하십시오.

  4. originentrystoring origins의 항목 중 하나와 same site이면 entry를 반환합니다.

    참고: 모든 항목이 가지는 동일 사이트 기준(즉, origins 옵션 없이 쓰기 요청을 수행할 때 부여되는 권한)은 이후 추가되는 어떠한 origins 목록 또는 globally disclosable 권한과 관계없이 항상 유지됩니다. 이는 아래의 Public Hash List 게이트보다 먼저 확인되므로, 동일 사이트 오리진은 해당 hashPHL에 있는지 여부와 관계없이 항목을 읽습니다. 여기서 동일 사이트는 하나의 신뢰 단위이므로, § 8.2 크로스 사이트 프로빙에서 보호하는 사이트 경계를 넘는 정보 공개가 발생하지 않습니다.

  5. originserializationentryorigins의 항목이면, entry를 반환합니다.

    참고: 명시적인 origins 목록에 있는 오리진은 항목이 PHL에 있을 필요 없이 해당 항목을 읽습니다. 저장 오리진은 이를 지정함으로써 제한된 공개 결정을 내렸으며(§ 3.5 리소스 가시성 향상§ 7 Cross-Origin-Storage-Allow-Origin 헤더 참조), 그 위에 별도의 전역 보편성 요구 사항을 추가하면 일반적인 제한 공유가 종종 독점적인 리소스에 대한 관련 없는 공개 큐레이션에 의존하게 됩니다. 이를 globally disclosable 게이트보다 먼저 확인하는 것은 이후의 전역 사용 가능 쓰기가 목록에 지정된 오리진의 접근 권한을 취소하지 않도록 합니다. § 8.2 크로스 사이트 프로빙을 참조하십시오.

  6. entryglobally disclosable이 true이면:

    1. entryhashPHL에 없으면 null을 반환합니다.

      참고: Public Hash List 게이트는 전역 권한 부여에만 적용됩니다. 이는 그렇지 않으면 웹상의 모든 오리진에 공개될 수 있는 유일한 경우입니다. globally disclosable이지만 hashPHL에 없는 항목은 이 권한만으로 자격을 얻는 오리진에 공개되지 않습니다. storing origins, 해당 동일 사이트 집합 또는 명시적인 origins 목록에 포함된 오리진은 이미 위에서 반환되었습니다.

    2. 사용자 에이전트가 이 요청에 GREASE 처리를 적용하기로 선택하면 null을 반환합니다.

      참고: GREASE 처리도 전역 권한 부여에만 적용됩니다. 위에서 확인한 권한은 이 단계에 도달하지 않습니다. storing origins 및 해당 동일 사이트 오리진은 하나의 신뢰 단위이며, 명시적인 origins 목록의 오리진은 Cross-Origin-Storage-Allow-Origin 헤더로 권한을 부여한 작성자가 의도적으로 지정한 것입니다.

    3. entry를 반환합니다.

  7. null을 반환합니다.

가용성 제어 적용COS 항목 또는 null entryorigin origin이 주어졌을 때 COS 항목 또는 null을 반환합니다:

  1. entryorigin을 사용하여 COS 공개 여부 결정을 실행한 결과를 반환합니다.

3.3. 파일 생성 및 쓰기

생성 요청 완료에 의해 생성된 FileSystemFileHandle에는 연관된 요청된 출처가 있으며, 이는 핸들을 통해 성공적으로 쓰기가 완료되면 검증 및 저장이 항목의 origins업그레이드하려고 시도할 값입니다.

COS 항목을 가리키는 모든 FileSystemFileHandle에는 또한 이를 얻은 출처인 연관된 COS 출처와, 해당 특정 핸들을 통해 getFile()이 항목의 바이트를 공개할 수 있는지를 규율하는 연관된 읽기 가능 불리언이 있습니다. 이미 가용성 게이팅을 통과한 읽기 요청 완료에서 반환된 핸들의 경우 true이고, 동일한 핸들에 대해 검증 및 저장이 성공하기 전까지는 생성 요청 완료에서 반환된 핸들의 경우 false입니다.

참고: 이는 의도적으로 각 핸들의 속성입니다. 생성 요청은 항목이 이미 존재하고 이미 "written" 상태인지 여부와 관계없이 핸들을 반환합니다(생성 요청 완료 참조). 따라서 항목 단위 규칙을 사용하면 모든 오리진이 requestFileHandle()create: true와 함께 호출하여 즉시 자신이 작성하지 않은 항목을 읽고, origins, PHL 멤버십 또는 GREASE 처리를 충족하지 않고도 해당 내용을 알아낼 수 있게 됩니다. 이 명세의 모든 공개 제어는 읽기 경로에 적용되므로, 항목별 제어를 적용하면 생성 요청이 모든 제어를 우회할 수 있습니다. 호출자가 먼저 올바른 바이트를 제공하도록 요구하면, 생성으로 얻은 핸들을 통한 성공적인 읽기는 호출자가 이미 가지고 있지 않은 어떠한 정보도 공개하지 않습니다.

생성 요청 완료promise result, COS 해시 hash, CrossOriginStorageRequestFileHandleOptions options, 전역 객체 globalRealm realm이 주어졌을 때 다음과 같이 수행합니다:

  1. requestedOriginsoptions["origins"]에 대해 요청된 origins 정규화를 실행한 결과로 설정합니다.

  2. requestedOrigins목록이면, requestedOriginsrequestedOriginsglobal을 사용하여 COS 범위 상한 적용을 실행한 결과와 COS 범위 상한 획득을 실행한 결과로 설정합니다.

  3. entryCOS 레지스트리에서 COS 항목으로 설정합니다. 해당 항목의 hashhash동등한 경우 해당 항목을 사용하며, 없으면 null로 설정합니다.

  4. entry가 null이면:

    1. entry를 새 COS 항목으로 설정합니다. 해당 항목의 hashhash이고, bytes는 null, state는 "pending", origins는 빈 목록, globally disclosable은 false, storing origins는 빈 집합입니다.

    2. 설정: COS 레지스트리[hash]를 entry로 설정합니다.

    참고: 새 항목은 명시적인 origins 권한 없이 시작하며 globally disclosable 상태가 아닙니다. requestedOrigins는 바이트가 작성되고 검증된 후 verify and store를 통해 리소스 가시성 업그레이드에서 아래에 적용됩니다. 이는 기존 항목을 찾는 요청과 동일합니다. 따라서 생성 요청은 가시성을 확장하기 전에 전체 바이트를 제공해야 합니다(§ 3.5 리소스 가시성 향상 참조).

  5. entrypending writer count를 1 증가시킵니다.

    참고: 이는 호출자가 createWritable()을 호출하지 않거나 생성된 스트림을 닫지 않더라도 handle을 아직 완료되지 않은 작성자로 추적합니다. 이러한 버려진 핸들은 이 메커니즘이 존재하기 전 버려진 진행 중 쓰기가 이미 entry를 영구적으로 "pending" 상태로 남긴 것과 동일하게 entry에 영구적으로 계산됩니다. verify and store를 참조하십시오.

  6. handleFileSystemFileHandle 생성의 결과로 설정합니다. 해당 locatorCross-Origin Storage 파일 시스템 내의 entry를 가리키며, realm에 있습니다.

  7. handleCOS originglobalrelevant settings objectorigin으로 설정합니다.

  8. handlerequested originsrequestedOrigins로 설정합니다.

  9. handlemay read를 false로 설정합니다.

    참고: handleentry가 이미 존재하는지 또는 이미 "written" 상태인지 여부와 관계없이 반환됩니다. 호출자는 여전히 handle을 통해 완전한 파일 바이트를 제공해야 합니다. 이를 통해 쓰기가 이전 존재 여부를 감지하는 데 사용되지 않도록 하며(§ 8.2 Cross-site probing 참조), 더 허용적인 origins 값 요청이 승인되기 전에 검증될 수 있도록 합니다(§ 3.5 Resource visibility upgrades 참조).

  10. 전역 작업을 큐에 추가합니다. DOM 조작 작업 소스에서 global을 대상으로 resulthandleresolve합니다.

요청된 origins 정규화는 (DOMString 또는 sequence<DOMString>) 또는 undefined인 origins가 주어졌을 때 "*", 목록origins, 또는 null을 반환합니다:

  1. origins존재하지 않으면 null을 반환합니다.

  2. origins가 "*"이면 "*"를 반환합니다.

  3. list를 « »로 설정합니다.

  4. 각각에 대해 originscandidate를 처리합니다(단일 문자열은 하나의 항목을 가진 목록으로 처리합니다):

    1. candidateOrigincandidate에 대해 기본 URL 파서를 실행한 결과인 origin으로 설정합니다.

      참고: COS 요청 검증은 이미 각 candidate가 파싱되어 non-opaque origin이 되는 것을 확인했습니다.

    2. listcandidateOrigin포함하지 않으면, candidateOriginlist추가합니다.

  5. list를 반환합니다.

참고: 이후 기존 항목에 대한 병합 전에 여기에서 중복을 제거하면, 항목이 처음 생성되는 순간부터 origins가 중복 없는 상태가 되며, 이후 모든 복제도 계속 중복 없는 상태를 유지합니다.

FileSystemWritableFileStreamcreateWritable()을 호출하여 얻어지고, 해당 핸들의 locatorCOS 항목을 가리키는 경우 닫히면, 사용자 에이전트는 닫기 작업의 promise가 이행되기 전에 아래의 verify and store 단계를 실행해야 합니다.

참고: 이는 닫기가 어떻게 트리거되었는지와 관계없이 적용됩니다. 명시적인 close() 호출이거나, 소스의 끝에 도달하는 pipeTo() 호출일 수 있으며, 후자의 경우 기본적으로 대상도 닫힙니다. [STREAMS]는 스트림이 닫히는 시점에서 두 경우를 구분하지 않으며, 이 알고리즘도 마찬가지입니다.

verify and store 단계는 닫힌 스트림의 핸들이 가리키는 COS 항목 entry, 완전히 작성된 바이트 시퀀스 bytes, 그리고 닫기 작업의 관련 설정 객체origin origin이 주어졌을 때 다음과 같습니다:

  1. computedValueentryalgorithm이 지정한 알고리즘을 사용하여 [WEBCRYPTO]에 따라 계산한 bytes의 소문자 16진수 다이제스트로 설정합니다.

  2. computedValueentryvalue와 정확히 같지 않으면:

    1. 닫기 작업의 promise를 "DataError" DOMException으로 거부합니다.

    2. 다음 단계들을 큐에 추가하여 Cross-Origin Storage 큐에 넣습니다:

      1. entrypending writer count를 1 감소시킵니다.

      2. entrystate가 "pending"이고 entrypending writer count가 0이면, entryhashCOS registry에서 제거합니다.

        참고: 이는 실패한 쓰기가 스스로 정리되도록 만드는 동작입니다. 동일한 hash에 대한 이후의 requestFileHandle() 호출은 다른 작성자가 더 이상 진행 중이 아니면 항목 자체를 찾지 못하고 일반적인 "NotFoundError"를 받습니다. 이 카운트는 동일한 hash에 대해 동시에 진행 중인 다른 작성자가 여전히 성공적으로 작성할 수 있는 항목을 삭제하지 않도록 보호합니다. 해당 작성자가 아직 진행 중이거나 이미 성공한 경우, 카운트가 아직 0에 도달하지 않았거나 entrystate가 더 이상 "pending"이 아니므로 이 단계는 아무 작업도 하지 않습니다. 이미 "written" 상태인 항목은 이후 작성자가 요청하고 실패하는 횟수와 관계없이 이 방식으로 제거될 수 없습니다. 한 번도 성공적으로 작성되지 않은 항목만 대상이 됩니다.

    3. 이 단계를 중단합니다.

  3. 다음 단계들을 큐에 추가하여 Cross-Origin Storage 큐에 넣습니다:

    1. entrybytesbytes로 설정합니다.

    2. entrystate를 "written"으로 설정합니다.

    3. origin을 이미 존재하지 않는 경우 entrystoring origins추가합니다.

    4. entrypending writer count를 1 감소시킵니다.

    5. entry와 핸들의 requested origins를 사용하여 resource visibility 업그레이드를 실행합니다.

    6. 핸들의 may read를 true로 설정합니다.

      참고: 읽을 수 있게 되는 것은 이 핸들뿐입니다. 같은 항목에 대한 다른 생성 요청에서 얻은 핸들이 쓰기를 완료하지 않았다면 해당 핸들은 읽을 수 없는 상태로 유지됩니다.

createWritable()COS 항목을 가리키는 FileSystemFileHandle에서 호출되면, FileSystemWritableFileStream을 생성해야 하며, 해당 스트림의 내용은 keepExistingData의 값과 관계없이, 그리고 가리키는 항목의 state와 관계없이 비어 있는 상태로 시작해야 합니다.

참고: [FS]는 그 외의 경우 keepExistingData를 기존 파일의 내용으로 스트림을 초기화하는 것으로 정의합니다. 여기에서 이를 허용하면 호출자가 자신이 소유하지 않았던 바이트에 대해 저장 오리진이 될 수 있습니다. 생성 요청은 항목이 이미 존재하는지 여부와 관계없이 핸들을 반환하므로, 호출자는 다른 오리진이 저장한 해시에 대해 쓰기 가능한 스트림을 열고, 아무것도 작성하지 않은 채 닫은 다음, 전달된 바이트가 요청된 값으로 해시되도록 만들 수 있습니다. 그러면 origins, Public Hash List, 그리고 GREASE 처리를 전혀 확인하지 않고 읽기 접근 권한을 부여하게 됩니다. 이는 각각 허용된 두 작업으로 구성된 가용성 제어 우회입니다. 모든 생성 요청에서 완전한 내용을 요구하도록 verify and store가 설계된 이유도 동일합니다.

참고: 따라서 아무런 쓰기 없이 닫힌 쓰기 가능 스트림은 빈 바이트 시퀀스를 가지며, 이는 호출자가 원하는 어떠한 항목에서도 요청된 값으로 해시되지 않습니다. 따라서 verify and store는 다른 불일치의 경우와 마찬가지로 "DataError" DOMException으로 거부합니다. 해당 경우에 구현이 대신 스토리지 또는 I/O 오류를 보고하면, 검증 결과를 관련 없는 오류 뒤에 숨기게 됩니다.

File System Standard [FS]는 아직 종속 명세가 FileSystemWritableFileStream의 닫기 단계에 추가적인 쓰기별 검증을 연결할 수 있도록 하는 확장 지점을 정의하지 않았습니다. 이러한 연결 지점이 존재할 때까지 이 절에서는 필요한 동작을 직접 설명하며, 향후 개정에서는 [FS]와 정식으로 통합할 예정입니다.

3.4. 가져온 리소스 저장

§ 9 다른 명세와의 통합에 나열된 호스트 통합은 FileSystemFileHandle을 거치지 않고 가져온 리소스를 저장합니다. 이러한 호스트 명세는 통합에서 요구하는 무결성 검사를 통해 가져온 바이트가 검사를 통과한 후 다음 알고리즘을 실행할 것으로 예상됩니다.

store a fetched resource in Cross-Origin Storageresponse response, byte sequence bytes, COS hash hash, "*", liststrings, 또는 null인 originsenvironment settings object settings가 주어진 경우:
  1. settingsglobal object에 대해 Cross-Origin Storage 권한 확인을 실행한 결과가 false이면 반환합니다.

  2. optionsorigins가 null이 아니면 «[ "origins" → origins ]»로, 그렇지 않으면 «[ ]»로 설정합니다.

  3. hashoptions를 사용하여 COS 요청 검증을 실행한 결과가 null이 아니면 반환합니다.

  4. computedValuehashalgorithm이 지정한 알고리즘을 사용하여 [WEBCRYPTO]에 따라 계산한 bytes의 소문자 16진수 다이제스트로 설정합니다.

  5. computedValuehashvalue와 정확히 같지 않으면 반환합니다.

    참고: 통합 자체의 무결성 메타데이터에는 여러 다이제스트가 나열될 수 있으며, 그중 하나와 일치하면 해당 조건을 만족합니다. 이 단계는 항목이 정확히 이러한 바이트가 생성하는 해시를 키로 사용하도록 보장합니다.

  6. requestedOriginsoptions["origins"]에 대해 요청된 origins 정규화를 실행한 결과로 설정합니다.

  7. requestedOrigins목록이면:

    1. internalResponseresponsefiltered response이면 responseinternal response로, 그렇지 않으면 response로 설정합니다.

    2. requestedOriginsrequestedOriginsinternalResponseheader list에 대해 COS 범위 상한 파싱을 실행한 결과를 사용하여 COS 범위 상한 적용을 실행한 결과로 설정합니다.

    참고: 상한은 가져온 리소스 자체의 response에서 가져오므로, 바이트를 제공하는 서버가 해당 리소스를 공개할 수 있는 오리진을 결정합니다. 로딩하는 DocumentCOS scope ceiling은 관여하지 않습니다. 해당 연산자는 리소스를 제어하지 않으며, 이를 통해 수신자를 승인하도록 허용하면 어떤 사이트든 다른 사이트의 자산을 자신이 선택한 오리진과 공유 가능하다고 선언할 수 있기 때문입니다. 사용자 에이전트는 내부 response에서 헤더를 읽으므로, opaque filtered response에서도 동작하며, 해당 헤더는 페이지에 절대 노출되지 않습니다.

  8. originsettingsorigin으로 설정합니다.

  9. 다음 단계들을 큐에 추가하여 Cross-Origin Storage 큐에 넣습니다:

    1. entryCOS registry에서 hash동등COS entry로 설정합니다. 없으면 null입니다.

    2. entry가 null이면:

      1. entry를 새 COS entry로 설정합니다. hashhash, bytes는 null, state는 "pending", origins는 빈 목록, globally disclosable은 false, storing origins는 빈 set입니다.

      2. Set the COS registry[hash] to entry.

    3. entrystate가 "pending"이면:

      1. entrybytesbytes로 설정합니다.

      2. entrystate를 "written"으로 설정합니다.

      참고: 여기에서 항목이 "pending"일 수 있는 이유는 동일한 hash에 대한 requestFileHandle() 작성자가 아직 진행 중일 수 있기 때문입니다. 해당 pending writer count는 변경하지 않으므로, 해당 작성자의 verify and store는 정상적으로 완료됩니다. 해당 바이트는 동일한 값으로 해시되므로 다시 저장해도 변경 사항이 없습니다.

    4. 아직 존재하지 않으면 originentrystoring origins추가합니다.

    5. entryrequestedOrigins를 사용하여 리소스 가시성 업그레이드를 실행합니다.

참고: verify and store와 마찬가지로, 저장 작업은 항목이 이미 "written" 상태인 경우에도 항상 완전한 바이트를 요구하므로 이전 존재 여부에 관한 정보를 노출하지 않습니다. 통합의 네트워크 가져오기 전 조회는 읽기 작업이며, availability gating§ 8.2 Cross-site probing의 프로빙 고려 사항이 적용됩니다.

3.5. 리소스 가시성 업그레이드

COS entry의 가시성은 업그레이드할 수 있지만 절대로 다운그레이드할 수 없습니다.

리소스 가시성을 업그레이드하기 위해 COS entry entry와 "*", listorigins 또는 null인 requestedOrigins가 주어진 경우:
  1. requestedOrigins가 null이면 반환합니다.

    참고: origins를 생략하면 이미 모든 entry가 가지고 있는 same-site 가용성만 요청합니다(COS disclosure 결정 참조). 따라서 추가할 항목이 없습니다.

  2. requestedOrigins가 "*"이면:

    1. entryglobally disclosable을 true로 설정합니다.

    2. 반환합니다.

    참고: 이는 전역 허가를 추가하며 entryorigins는 변경하지 않습니다. 이미 명시적인 origins list를 가진 entry는 이를 유지하므로, 해당 list의 모든 origin은 entry가 globally disclosable이 된 후에도 PHL과 무관한 액세스를 유지합니다. 이것이 두 허가가 별도로 저장되는 이유의 핵심입니다. globally disclosable을 참조하십시오.

  3. 각각에 대해 requestedOriginscandidateOrigin:

    1. entryorigins containscandidateOrigin이면 continue합니다.

    2. entryoriginssize가 사용자 에이전트의 maximum origins list length와 같으면 중단합니다.

      참고: 남아 있는 candidateOrigin 값은 이 업그레이드에서 조용히 삭제됩니다. 쓰기 작업 자체는 이미 성공했으며, 사용자 에이전트는 entry의 origins list가 용량에 도달했다는 콘솔 경고를 기록할 것으로 예상됩니다.

    3. Append candidateOriginentryorigins에 추가합니다.

참고: 업그레이드는 항상 origins에 추가하거나 globally disclosable을 true로 설정하는 작업만 수행합니다. list를 요청하는 작성자는 이미 globally disclosable인 entry도 그렇지 않은 entry와 동일하게 확장합니다. 두 허가는 독립적이기 때문입니다. 새로 나열된 origin은 "*" 허가가 유지되는 동안에도 PHL과 무관한 액세스를 얻습니다.

참고: 원래 저장자가 아닌 사이트를 포함하여 어떤 사이트든 entry의 origins를 확장할 수 있습니다. 단, entry의 hash와 일치하는 바이트를 제공해야 합니다. 이는 의도된 동작입니다. hash에 대해 올바른 바이트를 이미 보유한 사이트는 구성상 해당 hash가 나타내는 내용에 대해 원래 저장자와 동일한 권한을 가집니다.

3.5.1. 원래 저장자 액세스

originwriting을 성공적으로 완료하여 COS entry를 작성한 경우(즉, entry의 storing origins에 있는 모든 origin)는 이후 항상 requestFileHandle()을 통해 handle을 얻을 수 있습니다. 이는 entry의 origins 값과 무관하며, 해당 hashPHL에 있는지 여부와도 무관합니다. 이는 origin이 자신이 저장한 내용에 항상 액세스할 수 있는 Cache API의 모델과 유사합니다.

4. Cross-Origin Storage 파일 시스템

Cross-Origin Storage 파일 시스템은 어떤 origin의 버킷 파일 시스템이나 로컬 파일 시스템 액세스 루트와도 구별되는 파일 시스템 루트이며, 그 엔트리COS 레지스트리COS 엔트리 항목과 일대일로 대응한다.

Cross-Origin Storage 파일 시스템[FS]의 일반적인 호출별 권한 확인 모델을 사용하지 않는다. 즉, 해당 시스템에서 가져온 모든 FileSystemFileHandle은 스크립트에 반환되기 전에 이미 § 3.2 파일 읽기 또는 § 3.3 파일 생성 및 쓰기에 의해 완전히 권한이 부여되므로, 이러한 핸들에서 getFile()이나 createWritable()을 호출해도 추가 권한 프롬프트가 실행되지 않는다.

따라서 이러한 핸들에서 queryPermission()requestPermission()은 절대로 "prompt"를 보고해서는 안 된다. 프롬프트가 표시될 수 없기 때문이다. 생성 모드로 생성 요청을 통해 가져오지 않은 핸들에서는 "denied"를 보고해야 하며, 그 외에는 "granted"를 보고해야 한다.

주: 쓰기는 핸들에 실제로 부족할 수 있는 유일한 기능이다. 생성 요청만이 쓰기를 수행할 수 있는 핸들을 생성하므로, 다른 핸들의 쓰기 모드에 대해 "granted"를 보고하면 createWritable()이 거부할 기능이 있다고 주장하는 셈이다. 읽기는 "granted"로 유지된다. 읽을 수 있는 핸들을 가진 호출자는 이를 통해 읽을 수 있기 때문이다. 요청으로는 어느 쪽의 답도 변경할 수 없다. 표시할 프롬프트가 없고 권한 부여를 기록할 상태도 없기 때문이다.

getFile()COS 엔트리를 가리키는 FileSystemFileHandle에서 호출했을 때 해당 엔트리의 읽기가 허용됨이 false이면 "NotAllowedError" DOMException으로 거부되어야 한다. 여기에는 서로 다른 두 가지 경우가 포함된다:

핸들의 읽기가 허용됨이 true가 되면 해당 핸들에서 호출된 getFile()은 가리키는 엔트리의 바이트를 내용으로 하는 File을 반환한다. 이는 [FS]가 이미 파일 엔트리바이너리 데이터가 해당 바이트인 경우에 대해 정의한 동작과 정확히 같다.

COS 엔트리를 가리키는 FileSystemFileHandle파일 시스템 로케이터를 가지며, 그 경로는 하나의 문자열을 포함하는 목록이다. 이 문자열은 엔트리의 COS 해시이며, 그 루트Cross-Origin Storage 파일 시스템이다.

주: [FS]name을 핸들 로케이터의 경로에서 마지막 경로 구성 요소로 정의하므로, 이는 name도 결정한다. 즉, 이는 해시이다. 엔트리에는 고유한 이름이 없고 해시가 엔트리가 가진 유일한 식별자이므로, 해시를 보고하는 것은 빈 문자열이 버리는 정보를 전달한다.

엔트리에는 이름도 포함 디렉터리도 없으므로 [FS]의 구조적 표면 대부분은 작동할 대상이 없다. 예외는 식별성이며, 이는 콘텐츠 주소 지정 엔트리가 항상 답할 수 있는 유일한 질문이다. COS 레지스트리COS 해시마다 최대 하나의 COS 엔트리를 보유하므로, 두 핸들은 해시가 같을 때 정확히 동일한 엔트리를 가리킨다.

isSameEntry()COS 엔트리를 가리키는 FileSystemFileHandle에서 호출하고, 인수 역시 COS 엔트리를 가리키며 동일한 origin에서 가져온 것이라면, 두 핸들의 COS 해시 항목이 같을 때 true를 반환하고, 그렇지 않으면 false를 반환해야 한다.

주: 이를 거부하면 사용자 에이전트가 이미 보유한 정보를 버리게 된다.

isSameEntry()를 호출하는 origin이 가져오지 않은 인수를 사용하거나, Cross-Origin Storage 파일 시스템이 아닌 파일 시스템을 가리키는 인수를 사용하면 거부해야 한다.

주: 이 경우 false를 반환하면 두 핸들이 서로 다른 엔트리를 가리킨다고 주장하게 되며, 이는 호출 origin이 검사할 권리가 없는 핸들에 대한 주장이다. 거부는 비교를 수행할 수 없었다는 것만을 의미한다.

COS 엔트리를 가리키는 FileSystemFileHandle에서 move()remove()를 호출하면 "NotAllowedError" DOMException으로 거부되어야 하며, 엔트리를 변경하지 않아야 한다.

주: 엔트리는 해당 엔트리의 저장 origin마다 공유되므로, 삭제를 허용하면 한 사이트가 다른 사이트가 의존하는 데이터를 파괴할 수 있다. 삭제는 제거 및 사용자의 자체 저장소 제어에 속한다. 엔트리는 COS 해시로 이름이 지정되고 포함 디렉터리가 없으므로 이름 변경이나 부모 변경은 수행할 대상이 없다.

주: 이 작성 시점에 두 메서드 모두 [FS]나 File System Access API에 의해 정의되어 있지 않으므로 (WICG/file-system-access#214), 오류 이름은 removeEntry()를 따른다. 이는 [FS]가 엔트리 삭제를 위해 정의한 연산으로, 읽기-쓰기 액세스가 부여되지 않으면 액세스 결과의 오류 이름으로 거부한다. 여기서 거부하는 것이 정확한 동작이다. 연산은 의미가 있지만 허용되지 않는다.

createSyncAccessHandle()에는 여기서 별도의 규칙이 필요하지 않다. 핸들이 버킷 파일 시스템에 속하지 않을 때마다 그 단계에서 "InvalidStateError" DOMException으로 거부하기 때문이다. Cross-Origin Storage 파일 시스템은 어떤 origin의 것과도 구별되는 파일 시스템 루트이므로, [FS]가 이미 거부와 그 이름을 모두 결정한다.

주: 이 결과는 이 명세가 독립적으로도 원하는 결과이다. FileSystemSyncAccessHandle은 호출자에게 쓰기 가능한 파일 디스크립터를 제공하며, 이를 통해 호출자는 저장된 COS 해시와 연결된 엔트리의 바이트를 변경할 수 있다. 또한 엔트리가 공개되는 다른 모든 origin도 동일한 바이트를 읽는다.

4.1. 핸들 전송

FileSystemFileHandle직렬화 가능한 객체[FS]이므로, COS 엔트리를 가리키는 핸들을 다른 환경 설정 객체로 전달할 수 있다. 예를 들어 postMessage(message, options)를 사용할 수 있다. 이는 requestFileHandle()과 더불어 이러한 핸들을 얻는 두 번째 방법이므로, 여기에서도 이를 제한한다.

직렬화 단계COS 엔트리를 가리키는 FileSystemFileHandle에 대해 valueserialized가 주어졌을 때, 추가로 다음을 수행한다:

  1. serialized.[[COSOrigin]]을 valueCOS origin으로 설정한다.

  2. serialized.[[COSMayRead]]를 value읽기 가능 여부로 설정한다.

serialized, valuerealm이 주어졌을 때 역직렬화 단계는 추가로 다음을 수행한다:

  1. serialized.[[COSOrigin]]이 realm환경 설정 객체origin동일 출처이 아니면, "DataCloneError" DOMException을 throw한다.

  2. valueCOS originserialized.[[COSOrigin]]으로 설정한다.

  3. value읽기 가능 여부serialized.[[COSMayRead]]로 설정한다.

주: 동일 출처 확인이 없다면, 전송을 통해 이 명세의 모든 정보 공개 제어를 한 번에 무력화할 수 있다. 읽기 가능 여부가 true인 핸들은 이미 가용성 게이팅 적용이를 요청한 origin에 대해 통과했다. 이를 다른 origin에 게시하면 해당 origin은 origin, PHL 멤버십 또는 GREASE가 이에 대해 평가되기도 전에 엔트리의 바이트를 받게 된다. 이는 핸들이 동일 출처 수신자에게만 유용하다는 File System Standard의 기존 처리 방식과 일치한다.

주: 읽기 가능 여부는 핸들과 함께 전달되므로, 아직 쓰기를 수행하지 않은 생성 요청 핸들은 전송 후에도 읽을 수 없으며, 읽기 요청 핸들은 다시 게이팅되지 않고 읽을 수 있는 상태로 유지된다. 도착 시 다시 게이팅하면 호출자가 동일한 핸들을 전송하여 가용성을 반복적으로 탐색할 수 있게 된다.

5. 저장소 관리

5.1. 저장소 제한

사용자 에이전트는 하나의 origin성공적인 쓰기를 통해 COS 레지스트리에 기여할 수 있는 총 바이트 수에 제한을 두어야 한다. 이는 단일 origin이 다른 origin의 엔트리를 제거하려는 시도로 캐시를 가득 채우는 것을 방지하기 위함이다. 구체적인 한도는 구현에 따라 정의된다. origin의 쓰기가 한도를 초과하면 사용자 에이전트는 "QuotaExceededError" DOMException으로 쓰기를 거부해야 하며 콘솔에 경고를 기록해야 한다(should).

주: 엔트리는 콘텐츠 주소 지정 가능하므로, 동일한 해시 아래에 동일한 바이트를 반복해서 쓰는 origin은 첫 번째 성공적인 쓰기를 초과하는 추가 할당량을 소비하지 않는다. § 2.2 COS 엔트리를 참조하라.

사용자 에이전트는 또한 구현에 따라 정의되는 최대 origin 목록 길이를 가지며, 이는 단일 origins 목록에 포함될 수 있는 origin 개수를 제한하는 양의 정수이다. 이는 목록이 처음 제공될 때(COS 요청 검증 참조)와 나중에 기존 엔트리에 병합될 때(리소스 가시성 업그레이드 참조) 모두 적용되므로, 단일 호출도 시간이 지남에 따른 여러 호출의 누적 효과도 엔트리의 origins를 한도 없이 늘릴 수 없다. 메모리 사용을 제한하는 것 외에도, 이는 origin 목록이 "*"의 미신고 대체물로 사용되는 것을 방지한다. § 8.2 교차 사이트 탐색을 참조하라.

이 한도를 초과하는 경우는 두 지점에서 서로 다르게 처리되는데, 두 호출이 작업 내에서 매우 다른 시점에 발생하기 때문이다:

5.2. 축출

이 절은 비규범적입니다.

저장소 압박 상황에서 사용자 에이전트는 COS 레지스트리에서 엔트리를 제거할 수 있다(may). 예를 들어 각 엔트리에 가장 최근에 접근한 저장 origin들에 걸쳐 최소 최근 사용(least-recently-used) 정책을 사용할 수 있다. 사용자 에이전트는 사용자가 어떤 파일이 저장되어 있는지, 어떤 origin이 각 파일에 접근했는지 확인하고 엔트리를 수동으로 삭제하거나 모든 Cross-Origin Storage 데이터를 지울 수 있는 설정 UI를 제공할 것으로 기대된다.

사용자가 origin의 사이트 데이터를 지울 때, 사용자 에이전트는 해당 origin이 나타나는 모든 저장 origin 집합에서 그 origin을 제거해야 한다(should). 그 제거 이후, COS 엔트리저장 origin이 비어 있다면, 사용자 에이전트는 해당 엔트리를 삭제 대상으로 고려할 수 있다(may).

5.3. 수동으로 추가된 항목

이 절은 비규범적입니다.

앞서 설명한 설정 UI는 사용자가 디스크에 이미 보유한 파일을 Cross-Origin Storage에 직접 추가하도록 허용할 수 있다(예를 들어 어떤 웹사이트와도 무관하게 사용자가 다운로드한 AI 모델). 이때 어떤 스크립트도 requestFileHandle()을 호출하지 않는다. 이러한 엔트리에는 해당 쓰기를 귀속시킬 요청 origin이 없으므로, 명령형 API만으로는 답할 수 없는 두 가지 질문이 제기된다:

이 방법으로 추가된 후 상태가 "written"인 엔트리는 그 밖의 면에서는 웹사이트가 requestFileHandle()을 통해 작성한 엔트리와 구별되지 않는다. 동일한 가용성 게이팅가시성 업그레이드 규칙이 동일한 권한을 가진 다른 엔트리와 정확히 동일하게 적용된다. 여기에는 엔트리가 전역 공개 가능하게 되는 경우마다 PHL에 속하는지 확인하는 것도 포함된다. 이는 수동 추가의 기본값이다.

5.4. 출처 메타데이터

이 절은 비규범적입니다.

COS 엔트리는 그 바이트가 어디에서 왔는지에 관한 어떠한 정보도 의도적으로 기록하지 않는다. 식별자는 해시만으로 결정된다. 즉, 얼마나 많은 origin이 저장했는지 또는 얼마나 많은 URL에서 가져왔는지와 관계없이 동일한 바이트는 동일한 엔트리이다(§ 2.2 COS 엔트리 참조). URL은 한 작성자의 가져오기에 대한 속성이므로, 여러 origin이 작성한 엔트리에 대해 하나를 선택할 비자의적 방법이 없다. 또한 바이트와 같은 방식으로 검증할 수도 없으며(§ 8.1 리소스 무결성 참조), origin의 대략적인 값보다 사용자의 브라우징에 대해 훨씬 더 많은 정보를 담고 있다. 저장 origin이 제공하는 값은 경로나 쿼리 문자열로 특정 문서, 계정 또는 세션을 식별할 수 있기 때문이다. 따라서 이를 엔트리에 기록하면 origins§ 8.3 가용성 게이팅이 부과하도록 마련된 공개 제한을 우회하여 엔트로피가 높은 신호를 전달하게 된다.

그럼에도 이를 원하고 싶어 하는 동기는 실제로 존재한다. § 5.2 제거에 설명된 설정 UI에서 수 기가바이트의 파일을 보고 있는 사용자는 물론, 왜 requestFileHandle() 호출이 실패했는지 디버깅하는 개발자도 파일이 어디에서 왔는지 알고 싶어 할 것이다. 사용자 에이전트는 엔트리와 함께 구현에만 비공개인 출처 기록을 유지하는 방식으로 이를 제공할 수 있다. 예를 들어 각 저장 origin이 바이트를 어디에서 가져왔는지와 그 시점을 기록할 수 있다. 단, 해당 기록은 엔트리 외부에 유지되는 사용자 에이전트 상태로 취급되어야 한다:

이러한 기록은 콘텐츠에 보이지 않으므로, 사용자 에이전트가 기록을 유지하는지 여부와 얼마나 많이 유지하는지는 전적으로 구현에 맡겨진다. 이 명세의 어떤 내용도 이에 의존하지 않으며, 사이트는 그 존재 여부를 감지할 수 없다.

6. 권한 정책 통합

이 명세는 "cross-origin-storage" 문자열로 식별되는 정책 제어 기능 [permissions-policy]을 정의한다. 기본 허용 목록은 self이다.

[permissions-policy]Document에 대해 사용이 허용됨을 정의하지만, CrossOriginStorageManager는 자체 Document가 없는 WorkerGlobalScope에도 노출된다. 따라서 확인은 호출하는 전역 객체를 대상으로 표현한다. worker 전역 객체는 자신을 소유하는 Document를 전이적으로 확인하며, 그 모든 객체가 기능을 허용해야 한다.

전역 객체 global이 주어졌을 때 Cross-Origin Storage 권한 확인은 다음 boolean을 반환한다:
  1. globalWindow 객체이면:

    1. documentglobal연결된 Document로 설정한다.

    2. document가 null이면 false를 반환한다.

    3. document가 "cross-origin-storage" 정책 제어 기능사용하도록 허용되지 않았으면, false를 반환한다.

    4. true를 반환한다.

  2. globalWorkerGlobalScope 객체이면:

    1. ownersglobal소유자 집합으로 설정한다.

    2. owners비어 있으면, false를 반환한다.

    3. owner에 대해 owners를 순회한다:

      1. ownerDocument이고 owner가 "cross-origin-storage" 정책 제어 기능사용하도록 허용되지 않았으면, false를 반환한다.

      2. ownerWorkerGlobalScope 객체이고, owner가 주어진 Cross-Origin Storage 권한 확인을 실행한 결과가 false이면 false를 반환한다.

    4. true를 반환한다.

  3. false를 반환한다.

이 알고리즘이 false를 반환하는 전역 객체에서 수행되는 모든 requestFileHandle() 호출은 해시 검증, 레지스트리 조회 또는 쓰기가 수행되기 전에 "NotAllowedError" DOMException으로 거부된다.

주: 소유자 집합을 통해 확인하는 것은 기능이 이름만 opt-out 가능한 상태가 되는 것을 방지한다. blob: URL에서 생성된 worker는 생성한 페이지의 origin에서 실행되며 해당 페이지의 Cross-Origin Storage 보기를 정확히 공유한다(§ 3 CrossOriginStorageManager 인터페이스 참조). 따라서 전역 객체 자체의 Document만 확인하는 검사는 모든 worker에서 자명하게 통과하게 된다. 또한 다른 사항은 전혀 변경하지 않고 호출을 new Worker(URL.createObjectURL(&hellip;))로 옮기기만 해도 cross-origin-storage=() 정책을 피할 수 있게 된다.

주: ServiceWorkerGlobalScope소유자 집합은 비어 있으므로 이 알고리즘은 그곳에서 false를 반환한다. 이는 소유자 집합의 의미에 따른 것이다. 이는 worker가 생성될 때 채워지고 해당 worker가 여전히 적극적으로 필요한지 결정하기 위해 조회되는 활성 상태 관계이다. 서비스 worker에는 어떤 Document와도 그러한 관계가 의도적으로 없다. 등록은 유지되고, 사용자 에이전트는 이벤트에 응답하여 전역 객체를 시작하며, 서비스 worker 클라이언트가 전혀 없는 상태에서도 실행될 수 있다. 따라서 register()를 호출한 클라이언트는 등록 시점에는 알 수 있지만, 전역 객체가 실행될 때는 보통 이미 사라져 있으며, 하나의 실행 중인 서비스 worker가 정책이 서로 일치하지 않을 수 있는 여러 클라이언트를 처리한다.

주: 서비스 worker를 다루려면 캡처된 정책이 필요하며, 그 작업은 [permissions-policy][service-workers]에 속한다. 이 명세가 선호하는 형태는 서비스 worker의 정책을 자체 스크립트 응답의 Permissions-Policy 헤더에서 도출하는 것이다. 정책 컨테이너가 이미 해당 응답의 CSP를 전달하는 방식과 같다. 이렇게 하면 정책은 origin의 통제 아래 유지되며 모든 업데이트 확인 시 다시 평가된다. 등록하는 클라이언트의 정책을 스냅샷으로 저장하면 opt-out이 오래된 상태가 된다. 헤더에서 기능을 제거해도 등록이 업데이트될 때까지 적용되지 않기 때문이다. 이러한 모델이 마련되기 전까지는 닫힌 방향으로 실패하는 것만이 opt-out을 우회하는 데 사용할 수 없는 답이다.

주: SharedWorkerGlobalScope소유자 집합에는 서로 다른 정책을 가진 여러 Document가 포함될 수 있으며 worker의 수명 동안 소유자가 추가되거나 제거된다. 모든 소유자가 기능을 허용하도록 요구하면 기능을 허용하지 않는 소유자 하나가 전체 shared worker에서 Cross-Origin Storage를 비활성화하며, 그 결과는 두 requestFileHandle() 호출 사이에도 변경될 수 있다. 반대로 허용하는 소유자 하나만 요구하면 기능을 허용하는 문서가 허용하지 않는 문서를 대신하여 기능을 다시 활성화할 수 있다.

7. Cross-Origin-Storage-Allow-Origin 헤더

COS 엔트리origins 목록은 쓰기 origin이 제어하지 않는 origin에도 공개될 수 있지만, 해당 목록은 스크립트(origins를 통해) 또는 마크업으로 선언되며, 스크립트 또는 마크업 삽입에 성공한 공격자는 둘 중 어느 것이든 설정할 수 있다. 바이트가 공개되는 origin의 운영자에 선언을 귀속시키기 위해, 삽입된 콘텐츠가 위조할 수 없는 형태로, 이 명세는 그러한 선언이 지정할 수 있는 origin을 제한하는 응답 헤더를 정의한다.

Cross-Origin-Storage-Allow-Origin 응답 헤더는 COS 범위 상한을 전달한다. 이는 쓰기가 동일 사이트가 아닌 origins 목록에서 지정할 수 있는 origin집합이다. 바이트를 제공하는 주체가 헤더를 보내므로, 헤더는 공개되는 바이트 뒤에 있는 응답에서 읽힌다:

선언된 목록에는 상한이 교집합으로 적용되므로(COS 범위 상한 적용 참조), 상한은 선언의 범위를 좁히기만 한다.

주: 이 헤더는 바이트를 제공하는 측의 승인이다. 헤더가 지정하는 origin, 즉 최종 독자는 확인되지 않으며 아무것도 보내지 않는다. 지정된 origin은 다른 독자와 마찬가지로 나중에 해당 COS 해시에 대해 requestFileHandle()을 호출하여 참여할 뿐이다. 이는 Access-Control-Allow-Origin [FETCH]과는 반대 방향으로 동작한다. 해당 경우에는 리소스를 보유한 서버가 특정 origin의 읽기를 허용한다. 여기서는 바이트 제공자가 이후 Cross-Origin Storage에서 누가 읽을 수 있는지를 제한하며, 쓰기 페이지에 삽입된 콘텐츠는 제공자의 응답 헤더를 설정할 수 없으므로 그 제한을 확장할 수 없다.

주: 헤더는 목록 형식에만 적용된다. 동일 사이트 기본값은 교차 origin 수신자를 지정하지 않으므로 승인이 필요하지 않으며, "*" 형식은 읽기 경로에서 가용성 게이팅을 통해 공개 해시 목록과 대조하여 관리된다. 공개 해시 목록은 사용자별 비밀값으로 통과시킬 수 없으므로 쓰기 시점의 상한도 필요하지 않다. "*"에 헤더를 요구하면 공개 해시 목록이 이미 차단하는 범위를 넘어 아무것도 차단하지 못하면서, 설정 없이 전역 공유가 가능한 경우를 깨뜨리게 된다.

헤더 목록 headers가 주어졌을 때 COS 범위 상한 파싱은 다음 origin집합을 반환한다:
  1. valueheaders에서 "Cross-Origin-Storage-Allow-Origin"을 가져오고, 디코딩하고, 분할한 결과로 설정한다.

  2. value가 null이면 빈 집합을 반환한다.

  3. ceiling을 빈 집합으로 설정한다.

  4. value의 각 token에 대해:

    1. token에서 앞뒤 ASCII 공백을 제거한다.

    2. token이 빈 문자열이면 계속한다.

    3. token기본 URL 파서를 실행한 결과인 originorigin으로 설정한다.

    4. origin이 실패이거나 불투명 origin이면 빈 집합을 반환한다.

      주: 여기에는 origin으로 파싱되지 않는 "*" token도 포함된다. Cross-Origin-Storage-Allow-Origin 헤더는 유한한 구체적 origin 집합만 열거할 수 있다. "*"는 허용되는 값이 아니다. "모든 origin"이라는 상한은 삽입된 콘텐츠가 원하는 수신자를 선언하도록 허용하여 헤더의 전체 목적을 무력화하기 때문이다. 무제한 공개는 origins 형식의 "*"를 통해서만 이루어지며, 이는 공개 해시 목록에 의해 게이팅되고 이 헤더를 참조하지 않는다. 형식이 잘못되었거나 "*"를 포함하는 헤더는 헤더가 없는 경우와 정확히 마찬가지로 아무것도 승인하지 않는다. 실패 시 닫힌다.

    5. originceiling추가한다.

  5. ceiling을 반환한다.

주: 가져오고, 디코딩하고, 분할은 U+002C(,)에서 분할하므로 헤더 값의 origin은 쉼표로 구분된다. 이는 Timing-Allow-Origin [RESOURCE-TIMING] 및 목록 값을 가지는 HTTP 응답 헤더의 일반적인 관례와 일치한다. 반면 형제 관계인 crossoriginstorage HTML 콘텐츠 속성은 호스트 문법에 맞추기 위해 공백으로 구분된다. 둘 다 동일한 origin 집합으로 해석된다.

전역 객체 global이 주어졌을 때 COS 범위 상한 가져오기는 다음 origin집합을 반환한다:
  1. globalWindow 객체이면:

    1. documentglobal연결된 Document로 설정한다.

    2. document가 null이면 빈 집합을 반환한다.

    3. documentCOS 범위 상한을 반환한다.

  2. globalWorkerGlobalScope 객체이면:

    1. ownersglobal소유자 집합으로 설정한다.

    2. owners비어 있으면, 빈 집합을 반환한다.

    3. ceiling을 null로 설정한다.

    4. owners의 각 owner에 대해:

      1. ownerCeiling을 빈 집합으로 설정한다.

      2. ownerDocument이면, ownerCeilingownerCOS 범위 상한으로 설정한다.

      3. 그렇지 않고 ownerWorkerGlobalScope 객체이면, owner가 주어진 COS 범위 상한 가져오기의 결과로 ownerCeiling을 설정한다.

      4. ceiling이 null이면 ceilingownerCeiling으로 설정한다. 그렇지 않으면 ceilingownerCeiling교집합으로 ceiling을 설정한다.

    5. ceiling을 반환한다.

  3. 집합을 반환한다.

목록requestedOriginsorigin집합ceiling이 주어졌을 때 COS 범위 상한 적용은 다음 origin 목록 또는 null을 반환한다:
  1. requestedOrigins에서 ceiling포함하지 않는origin제거한다.

    주: COS 범위 상한에 없는 수신자는 삭제되지만 쓰기는 계속 성공한다. 이는 리소스 가시성 업그레이드에서 길이 초과 시 초과분을 삭제하는 방식과 일치한다. 사용자 에이전트는 삭제된 각 origin의 이름을 포함한 콘솔 경고를 기록할 것으로 기대된다.

  2. requestedOrigins비어 있으면, null을 반환한다.

    주: 모든 구성원이 삭제된 목록은 쓰기에 권한이 부여된 교차 origin 수신자가 없게 하므로 동일 사이트 기본값으로 되돌아간다. 바이트는 계속 저장되며 권한이 없는 공개만 차단된다.

  3. requestedOrigins를 반환한다.

모든 Document에는 COS 범위 상한이 있으며, 이는 origin집합이다. 이 값은 문서가 생성될 때 문서를 생성하는 데 사용된 응답헤더 목록을 주어 COS 범위 상한 파싱을 실행한 결과로 설정된다.

주: worker의 소유자 집합에 대해 교집합을 취하는 것은 Cross-Origin Storage 권한 확인을 반영한다. origin은 모든 소유 Document가 전이적으로 이를 승인한 경우에만 worker의 상한에 포함된다. blob: worker는 생성한 페이지의 origin 및 Cross-Origin Storage 보기를 정확히 공유하므로(§ 3 CrossOriginStorageManager 인터페이스 참조), worker 자체만 확인하는 상한은 모든 worker에서 비어 있게 된다. 또한 목록 범위 쓰기를 new Worker(URL.createObjectURL(&hellip;))로 옮기면 페이지가 승인한 수신자가 제거된다. 소유자들의 상한을 교집합으로 취하면 어느 한 소유자도 상한을 넓힐 수 없게 하면서 해당 승인을 보존한다.

DocumentCOS 범위 상한을 해당 응답에서 채우려면 [HTML]의 문서 생성 단계에 후크가 필요하다. 이는 [permissions-policy][CSP]가 응답 처리 시점에 채워지는 방식과 같다. 해당 후크가 마련될 때까지 이 절은 필요한 동작을 직접 설명하며, 향후 개정에서는 [FS]의 후크와 함께 이를 공식적으로 통합할 예정이다. 해당 후크는 § 3.3 파일 생성 및 쓰기에 언급되어 있다. 호스트 통합에는 이러한 후크가 필요하지 않다. 호스트 통합은 가져온 응답가져온 리소스를 Cross-Origin Storage에 저장에 전달하고, 해당 알고리즘이 응답에서 상한을 읽기 때문이다.

8. 개인정보 보호 및 보안 고려사항

이 절은 RFC 2119 키워드를 사용하는 부분을 제외하고 비규범적입니다. 저장소의 보안 및 개인정보 보호 설문지도 참조하십시오.

8.1. 리소스 무결성

모든 COS 엔트리는 암호화 해시를 키로 사용하며, 해당 바이트는 그 해시와 대조하여 검증된다(§ 3.3 파일 생성 및 쓰기 참조). 따라서 사이트는 requestFileHandle()을 통해 가져온 파일이 hash를 직접 가져왔을 때 얻게 되는 것과 정확히 동일한 바이트를 가진다는 것을 확신할 수 있다. 개발자는 Cross-Origin Storage의 내용을 열거하거나 해시를 이미 알고 있지 않은 상태에서 파일에 액세스할 수 없다.

COS 해시는 비밀이 아니다. 이는 이미 파일을 가지고 있는 사람이라면 누구나 쉽게 계산할 수 있는 콘텐츠 식별자이며, 이 명세가 대상으로 하는 널리 배포된 리소스 종류에서는 일반적으로 공개된 정보이다. 모델이나 라이브러리의 릴리스와 함께 게시되는 경우가 많다. 따라서 해시를 아는 것만으로도 엔트리를 조회하기에는 충분하지만, 그 자체로 액세스 권한이 부여되지는 않는다. 조회의 성공 여부는 전적으로 origins§ 8.3 가용성 게이팅에 의해 결정된다. 개발자는 공개되지 않은 해시를 액세스 제어 수단으로 취급해서는 안 된다. 특정 파일에 관심이 있는 공격자는 그 해시를 추측할 필요 없이 파일 자체를 얻기만 하면 되기 때문이다(§ 8.2 교차 사이트 탐색 참조).

8.2. 교차 사이트 프로빙

어떤 리소스가 좁은 범위의 사이트에서만 사용되는 경우, 그 리소스가 Cross-Origin Storage에 존재한다는 사실을 알아낼 수 있는 공격자는 사용자가 해당 사이트들 중 하나를 방문했을 가능성이 높다고 추론할 수 있다. requestFileHandle()이 존재 여부를 알아내는 메커니즘이므로, 각 호출은 사실상 탐색(probe)이다. 이 명세에는 탐색이 알아낼 수 있는 내용을 제한하는 두 가지 독립적인 메커니즘이 있다:

첫 번째 항목은 "선택된 origin 집합"이 웹 전체보다 의미 있게 작은 상태를 유지할 때만 성립한다. origins의 형태에는 호출자가 매우 많은 수의 origin을 열거하는 것을 막는 요소가 없다(예를 들어 공개된 인기 사이트 순위에서 조합한 목록). 이는 "*"만이 요구하는 의도적이고 명시적인 opt-in을 우회하면서 사실상 전역 공개에 근접하게 될 것이다. 최대 origin 목록 길이(§ 5.1 저장소 한도 참조)는 이를 제한한다. 진정한 다중 속성 사용 사례(공통 통제 하에 있는 소수의 관련 origin)에는 충분히 들어맞을 만큼 작으면서도 "모든 origin"에 대한 의미 있는 근사치에는 훨씬 못 미치는 한도는, 제한된 origin 형식의 origins가 "*"의 미신고 대체물로 사용되는 것을 방지한다.

사용자 에이전트는 추가로 단일 origin으로부터의 반복적인 requestFileHandle() 호출에 속도 제한을 걸거나 다른 방식으로 제한해야 하며(should), 탐색된 해시가 PHL에 속하는지와 무관하게 탐색 시도를 식별하고 차단하기 위해 기기 내 휴리스틱(예를 들어 사용자별로 생성된 것으로 보이는 해시에 대한 요청 패턴 감지)을 적용할 수 있다(may).

§ 9 다른 명세와의 통합에 있는 호스트 통합 중 하나가 수행하는 조회 또한 페이지에 오류를 드러내지 않더라도 마찬가지로 탐색이다. 사이트는 자신의 서버가 폴백 요청을 받았는지 여부를 관찰할 수 있는데, 이는 여기서 "찾을 수 없음" 결과가 전달하는 것과 동일한 단일 비트를 전달한다. 이러한 조회는 이 명세의 게이트가 막지 못하는 어떤 것도 공개하지 않으며, 그 게이트들은 변경 없이 그대로 적용된다. 다만 속도 제한은 이러한 표면으로부터의 조회가 requestFileHandle() 호출과 함께 집계될 때만 효과가 있다. 스크립트로 제어 가능한 통합은 루프 안에서 그만큼 쉽게 이를 실행할 수 있기 때문이다.

8.3. 가용성 게이팅

requestFileHandle() 읽기가 저장 origin 외부의 origin에서 성공하는지 여부는 항상 요청 origin이 엔트리를 읽도록 허용되는지에 달려 있으며, 이는 origins에 의해 결정된다. "*" 범위 엔트리에는 이와 독립적인 두 번째 질문도 적용된다. 즉, 사용자 에이전트가 엔트리가 존재한다는 사실 자체를 공개할 의향이 있는지이며, 이는 PHL 멤버십GREASE 적용에 의해 결정된다. 이러한 엔트리의 경우 두 조건이 모두 충족되어야 하며, 목록 범위 또는 동일 사이트 범위 엔트리에는 첫 번째 질문만 적용된다. 규범적 알고리즘은 § 3.2 파일 읽기를 참조하라. 따라서 "NotFoundError"는 리소스가 존재하지 않는다는 증거가 아니다. 리소스가 존재하지 않거나, 요청 origin이 범위를 벗어났거나, "*" 범위 리소스의 해시가 아직(또는 영원히) PHL에 없거나, GREASE 적용으로 인해 실제 긍정 결과가 억제되었음을 의미할 수 있다. 개발자는 "NotFoundError"를 "네트워크로 폴백"보다 더 구체적인 의미로 취급해서는 안 된다.

주: "*" 범위 엔트리의 공개는 현재 문맥에서 서드파티 쿠키를 설정하거나 읽을 수 있는 요청 origin으로 추가로 제한된다. 이러한 엔트리는 서드파티 쿠키를 사용할 수 없는 origin에는 PHL 멤버십과 관계없이 공개되지 않는다. 이는 PHL 멤버십만으로는 해결할 수 없는 허점을 막는다. 공격자는 그 자체로는 일반적이고 개별적으로 PHL 대상이 될 수 있는 리소스 중 어떤 부분집합을 기록할지 선택하여 사이트 간 식별자를 만들 수 있으며, 그 결과로 생성된 탐색이 일반적인 추적 쿠키보다 더 많은 정보를 제공하는지는 서드파티 쿠키의 사용 가능 여부가 결정하기 때문이다.

8.4. GREASE 적용

사용자 에이전트는 GREASE 적용(Generate Random Extensions And Sustain Extensibility)을 적용할 수 있다(may): § 8.3 가용성 게이팅이 그렇지 않았다면 공개를 허용했을 공개 가능한 엔트리에 대해 간혹 존재하지 않는 것처럼 응답하는 것이다. 이는 사이트가 실제 부재와 프라이버시 목적의 거짓 부정을 구별하기 어렵게 만드는 노이즈를 추가하며, 이는 UA Client Hints가 적용하는 기법과 유사하다.

GREASE 적용은 전역 공개 가능 부여만으로 자격을 갖춘 origin에만 적용되며, 이는 공개 해시 목록이 게이팅하는 경우와 동일하다(COS 공개 결정 참조). 사용자 에이전트는 이를 저장 origin, 그것과 동일 사이트인 origin, 또는 명시적인 origins 목록에 있는 origin에는 적용해서는 안 된다(must not).

GREASE 적용을 수행하는 사용자 에이전트는 해당 엔트리의 크기에 비례하는 판단으로 이를 수행해야 한다(must). 네트워크 가져오기로 폴백하는 비용이 저렴한 작은 엔트리의 경우, 간헐적인 거짓 부정은 합리적인 프라이버시 절충안이다. 사용자 에이전트는 그 크기로 인해 잘못된 재다운로드가 결과적인 프라이버시 이점에 비해 명백히 불균형한 엔트리(예를 들어 기가바이트 규모의 AI 모델 가중치)에는 GREASE 적용을 해서는 안 된다(must not). 그러한 경우 거짓 부정은 완전하고, 관찰 가능하며, 비용이 큰 재다운로드를 강제하기 때문이다.

8.5. 핑거프린팅

공격자가 Cross-Origin Storage 프로빙에서 추출할 수 있는 정보는 프로빙한 리소스가 얼마나 인기 있는지에 의해 제한됩니다. 일반적인 AI 모델이나 널리 사용되는 JavaScript 라이브러리처럼 매우 인기 있는 리소스를 사용자가 가지고 있다는 사실을 알아내더라도, 사용자가 이를 사용하는 (매우 많을 수도 있는) 사이트 중 하나를 방문했다는 사실만 드러납니다. 반면 희귀하거나 고유한 리소스를 사용자가 가지고 있다는 사실은 훨씬 더 많은 정보를 제공합니다. 사용자 에이전트는 해시가 의도적으로 사용자별로 고유하게 만들어진 것으로 보이는 리소스를 탐지하기 위해 기기 내 휴리스틱을 적용하고(예를 들어 하나의 사이트에서만 작성된 적이 있는 해시 또는 비정상적으로 자주 요청되는 해시), 명목상의 PHL 상태와 관계없이 이러한 패턴을 프로빙 시도로 취급할 것으로 예상됩니다.

9. 다른 명세와의 통합

이 절은 비규범적입니다.

여기서 정의하는 COS 레지스트리requestFileHandle()을 직접 거치지 않고도 네 가지 호스트 통합에서 접근할 수 있다. 각 통합은 자체 호스트 명세에서 정의된다. 이 명세는 공유되는 기본 개념(COS 해시, COS 엔트리, 가용성 게이팅공개 해시 목록)과 해당 통합이 기반으로 삼을 것으로 예상되는 가져온 리소스를 Cross-Origin Storage에 저장 단계를 정의한다.

설명을 위한 것일 뿐이지만, 다음은 동일한 전역 공유 리소스를 네 가지 형식 각각을 통해 Cross-Origin Storage에 사용하도록 선택한 예이다:

<script src="popular-library.js" integrity="sha256-abc123..." crossoriginstorage="*"></script>
import data from "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(*));
}
const response = await fetch("popular-resource.ext", {
  integrity: "sha256-abc123...",
  crossOriginStorage: "*",
});

이 스니펫들은 설명을 위한 것일 뿐이다. 이 문법 중 어느 것도 이 명세에서 정의하지 않는다. 각 형식에 대한 권위 있는 문법과 제한된 origins 목록을 표기하는 방법은 해당 호스트 명세에 속한다. 표기 방식은 의도적으로 서로 다르다. RequestInit 멤버는 sequence<DOMString>을 받을 수 있어 origins와 정확히 일치하는 반면, 속성 값, import 속성 값 및 CSS 수정자 인수는 텍스트만 전달할 수 있다.

네 가지 형식 모두 먼저 일치하는 공개 가능한 엔트리를 COS 레지스트리에서 확인한 뒤 네트워크 가져오기로 폴백하고, 성공적으로 가져와 무결성이 검증된 리소스를 COS 레지스트리에 저장하여 다른 origin이 재사용할 수 있도록 하는 처리 모델을 공유할 것으로 예상된다. 이는 requestFileHandle()이 수행하는 방식과 정확히 같다. 저장 단계는 가져온 리소스를 Cross-Origin Storage에 저장이며, 각 통합은 가져온 응답을 사용하여 이를 실행한다. 따라서 제한된 origins 값은 바이트를 제공하는 서버가 보낸 해당 리소스 응답의 Cross-Origin-Storage-Allow-Origin 헤더에 의해 제한된다(§ 7 Cross-Origin-Storage-Allow-Origin 헤더 참조). 이러한 통합에 대한 논의는 이 저장소의 이슈 추적기가 아니라, 해당 통합을 포함할 호스트 명세의 추적기에서 이루어져야 한다.

감사의 글

Tab Atkins-Bittner, Yash Raj Bharti 및 Joshua Lochner의 귀중한 피드백과 Kenji Baheux 및 Kevin Moore의 귀중한 영감과 아이디어에 깊이 감사드립니다.

이 명세에는 파일 시스템을 모델로 한 자료가 포함되어 있으며, 이는 W3C 소프트웨어 및 문서 라이선스에 따라 이용할 수 있습니다.

적합성

문서 규칙

적합성 요구사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현됩니다. 이 문서의 규범적 부분에 있는 핵심 단어 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY” 및 “OPTIONAL”은 RFC 2119에 설명된 대로 해석해야 합니다. 다만 가독성을 위해 이 명세에서는 이러한 단어가 모두 대문자로 표시되지는 않습니다.

이 명세의 모든 텍스트는 명시적으로 비규범적이라고 표시된 절, 예제 및 참고를 제외하고 규범적입니다. [RFC2119]

이 명세의 예제는 “예를 들어”라는 단어로 시작하거나 다음과 같이 class="example"을 사용하여 규범적 텍스트와 구분됩니다.

이는 정보 제공용 예제의 예입니다.

정보 제공용 참고는 “참고”라는 단어로 시작하며 다음과 같이 class="note"를 사용하여 규범적 텍스트와 구분됩니다.

참고, 이는 정보 제공용 참고입니다.

색인

이 명세에서 정의하는 용어

참조로 정의되는 용어

참조 문헌

규범적 참조 문헌

[DOM]
Anne van Kesteren. DOM 표준. 현행 표준. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript 언어 명세. URL: https://tc39.es/ecma262/multipage/
[FETCH]
Anne van Kesteren. Fetch 표준. 현행 표준. URL: https://fetch.spec.whatwg.org/
[FileAPI]
Marijn Kruisselbrink. File API. URL: https://w3c.github.io/FileAPI/
[FS]
Austin Sullivan. 파일 시스템 표준. 현행 표준. URL: https://fs.spec.whatwg.org/
[HTML]
Anne van Kesteren; 외. HTML 표준. 현행 표준. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 표준. 현행 표준. URL: https://infra.spec.whatwg.org/
[PERMISSIONS-POLICY]
Ian Clelland. 권한 정책. URL: https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner. 요구사항 수준을 나타내기 위해 RFC에서 사용하는 핵심 단어. 1997년 3월. 현재 최선의 관행. URL: https://datatracker.ietf.org/doc/html/rfc2119
[URL]
Anne van Kesteren. URL 표준. 현행 표준. URL: https://url.spec.whatwg.org/
[WEBCRYPTO]
Daniel Huigens. Web Cryptography 레벨 2. URL: https://w3c.github.io/webcrypto/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 표준. 현행 표준. URL: https://webidl.spec.whatwg.org/

비규범적 참조 문헌

[CSP]
Mike West; Antonio Sartori. 콘텐츠 보안 정책 레벨 3. URL: https://w3c.github.io/webappsec-csp/
[RESOURCE-TIMING]
Yoav Weiss; Noam Rosenthal. 리소스 타이밍. URL: https://w3c.github.io/resource-timing/
[SERVICE-WORKERS]
Monica CHINTALA; Yoshisato Yanagisawa. Service Workers Nightly. URL: https://w3c.github.io/ServiceWorker/
[SRI]
Frederik Braun. 서브리소스 무결성. URL: https://w3c.github.io/webappsec-subresource-integrity/
[STREAMS]
Adam Rice; 외. Streams 표준. 현행 표준. URL: https://streams.spec.whatwg.org/
[UA-CLIENT-HINTS]
User-Agent 클라이언트 힌트. 커뮤니티 그룹 보고서 초안. URL: https://wicg.github.io/ua-client-hints/

IDL 색인

[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;

이슈 색인

Public Hash List의 검색 프로토콜, 갱신 주기, 데이터 형식, 인기도 임계값 및 거버넌스는 [URL] Standard의 보조 데이터 파일인 public suffix list와 같은 방식으로, 이 명세의 보조 산출물로서 상세하게 설계되었습니다. 이 저장소의 Public Hash List explainer를 참조하십시오. 이 설계는 Public Suffix List의 공급업체 간 협력 및 롤링 릴리스 선례를 모델로 하여 WHATWG에 의한 거버넌스를 제안하며, 독립적으로 입증된 보편성에 기반한 승인 기준을 사용합니다. 이는 위에서 설명한 k-익명성 스타일 기준을 구체적으로 적용한 사례이며, hash가 승인되는 과정의 일부로 오프라인에서 한 번만 적용되므로 사용자 에이전트는 각 쿼리마다 이를 반복하지 않습니다. 이 제안 외부에서는 아직 이러한 내용이 확립되지 않았습니다. 이 list 자체에 대한 초기 비규범적 코드 프로토타입은 현재 이 저장소의 public-hash-list/implementation/에 있으며, 전용 공급업체 간 저장소는 PHL explainer에서 설명하는 거버넌스 목표로 남아 있습니다. 이 명세는 hash가 on the PHL인지 여부에만 의존하므로, list의 검색 메커니즘, 거버넌스 모델 또는 나머지 설계가 어떻게 발전하더라도 올바른 상태를 유지합니다.
File System Standard [FS]는 아직 종속 명세가 FileSystemWritableFileStream의 closing steps에 추가적인 쓰기별 검증을 연결할 수 있는 확장 지점을 정의하지 않았습니다. 이러한 hook이 존재할 때까지 이 절에서는 필요한 동작을 직접 설명합니다. 향후 개정판에서는 [FS]와 정식으로 통합될 것으로 예상됩니다.
DocumentCOS scope ceiling을 해당 response에서 채우려면 [HTML]의 document 생성 단계에 hook이 필요합니다. 이는 [permissions-policy][CSP]가 response 처리 시점에 채워지는 방식과 동일합니다. 해당 hook이 존재할 때까지 이 절에서는 필요한 동작을 직접 설명합니다. 향후 개정판에서는 [FS] hook과 함께 이를 정식으로 통합할 것으로 예상됩니다. 이는 § 3.3 Creating and writing files에서 언급된 것입니다. Host 통합에는 이러한 hook이 필요하지 않습니다. 가져온 responsestore a fetched resource in Cross-Origin Storage에 전달하면, 해당 과정이 response에서 ceiling을 읽습니다.