교차 출처 저장소

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

이 버전:
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 모델에 의존하는 경우, 출처별로 분할된 저장소는 사용자가 해당 모델을 두 번 다운로드하여 보관하도록 강제한다. 이는 사용자의 대역폭, 저장 공간, 배터리뿐 아니라 네트워크 전체에도 낭비이다.

교차 출처 저장소(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만 정의한다. 관련 제안은 동일한 기반 캐시를 선언적 마크업과 통합한다. 즉, linkscript의 HTML crossoriginstorage 속성, crossOriginStorage JavaScript 가져오기 속성, CSS cross-origin-storage() <request-url-modifier>이며, 각각 해당 호스트 언어의 자체 명세에서 정의한다. § 8 다른 명세와의 통합을 참조한다.

2. 개념

2.1. 해시

COS 해시는 다음 항목을 포함하는 구조체이다.

알고리즘

[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 항목에는 다음 항목이 있다.

해시

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;

NavigatorWorkerNavigator 객체에는 연결된 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) 메서드 단계는 다음과 같다.
  1. result새 프로미스로 둔다.

  2. realmthis관련 Realm으로 둔다.

  3. globalthis관련 전역 객체로 둔다.

  4. originthis에 연결된 출처로 둔다.

  5. global에 연결된 Document가 있는 경우 해당 문서가 "cross-origin-storage" 정책 제어 기능사용하도록 허용되지 않았다면:

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

    2. result를 반환한다.

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

  7. validationFailure가 null이 아니면:

    1. global이 주어졌을 때 DOM 조작 태스크 소스전역 태스크를 대기열에 추가하여 resultvalidationFailure거부한다.

    2. result를 반환한다.

  8. 다음 단계를 교차 출처 저장소 큐대기열에 추가한다.

    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. 파일 읽기

프로미스 result, COS 해시 hash, 출처 origin, 전역 객체 global, Realm realm이 주어졌을 때 읽기 요청을 완료하려면:
  1. entryCOS 레지스트리에서 해시hash동등한 COS 항목이 있으면 해당 항목으로, 그렇지 않으면 null로 둔다.

  2. entry가 null이 아니고 entry상태가 "pending"이면:

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

    2. 반환한다.

    참고: 쓰기가 진행 중인 해시는 의도적으로 존재하지 않는 해시와 다르게 동작한다. 이를 통해 호출자가 진행 중인 쓰기를 실제 캐시 미스로 오인하고, 오직 해당 파일을 쓰기 위한 목적으로 매우 큰 파일의 중복 동시 다운로드를 시작하지 않도록 한다. § 3.3 파일 생성 및 쓰기를 참조한다.

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

  4. disclosableEntry가 null이면:

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

    2. 반환한다.

  5. handlerealm에서 교차 출처 저장소 파일 시스템 내부의 disclosableEntry를 가리키는 로케이터를 가진 FileSystemFileHandle을 생성한 결과로 둔다 [FS].

  6. global이 주어졌을 때 DOM 조작 태스크 소스전역 태스크를 대기열에 추가하여 resulthandle이행한다.

COS 항목 또는 null인 entry출처 origin이 주어졌을 때 COS 공개 여부를 결정하려면 COS 항목 또는 null을 반환한다.
  1. entry가 null이면 null을 반환한다.

  2. 단언: entry상태는 "written"이다.

  3. originentry저장 출처에 포함되어 있으면 entry를 반환한다.

    참고: 원래 저장자와 해당 항목을 직접 성공적으로 작성한 모든 출처는 언제든 다시 읽을 수 있다. § 3.4.1 원래 저장자의 접근을 참조한다.

  4. entry출처가 "*"이면:

    1. entry해시PHL에 있지 않으면 null을 반환한다.

      참고: 공개 해시 목록 게이트는 전역 범위 항목, 즉 그렇지 않으면 공개가 웹의 모든 출처에 도달할 수 있는 유일한 경우에만 적용된다. 아래의 목록 범위 및 동일 사이트 범위에는 적용되지 않는다. 해당 범위에서는 저장 출처가 이미 명시적이고 제한된 공개 결정을 내렸으며, 별도의 전역 보편성을 추가로 요구하면 일반적인 제한 공유(§ 3.4 리소스 가시성 상향 참조)가 흔히 독점 리소스인 항목에 대한 무관한 공개 선별에 의존하게 된다. § 7.2 교차 사이트 탐색을 참조한다.

    2. entry를 반환한다.

  5. entry출처목록이면:

    1. origin직렬화가 해당 목록의 항목이면 entry를 반환한다.

    2. null을 반환한다.

  6. 단언: entry출처는 null이다.

  7. originentry저장 출처 중 어떤 항목과 동일 사이트이면 entry를 반환한다.

  8. null을 반환한다.

COS 항목 또는 null인 entry출처 origin이 주어졌을 때 가용성 게이팅을 적용하려면 COS 항목 또는 null을 반환한다.
  1. disclosableentryorigin이 주어졌을 때 COS 공개 여부 결정을 실행한 결과로 둔다.

  2. disclosable이 null이면 null을 반환한다.

  3. origindisclosable저장 출처에 포함되어 있으면 disclosable을 반환한다.

  4. 사용자 에이전트가 이 요청에 GREASE 적용을 선택하면 null을 반환한다.

  5. disclosable을 반환한다.

3.3. 파일 생성 및 쓰기

생성 요청 완료에 의해 생성된 FileSystemFileHandle에는 연결된 요청된 출처가 있다. 이는 핸들을 통한 쓰기가 성공적으로 완료된 뒤 검증 및 저장이 항목의 출처상향하려고 시도할 값이다.

프로미스 result, COS 해시 hash, CrossOriginStorageRequestFileHandleOptions options, 전역 객체 global, Realm realm이 주어졌을 때 생성 요청을 완료하려면:
  1. requestedOriginsoptions["origins"]가 주어졌을 때 요청된 출처 정규화를 실행한 결과로 둔다.

  2. entryCOS 레지스트리에서 해시hash동등한 COS 항목이 있으면 해당 항목으로, 그렇지 않으면 null로 둔다.

  3. entry가 null이면:

    1. entry를 다음과 같은 새 COS 항목으로 설정한다. 해시hash, 바이트는 null, 상태는 "pending", 출처requestedOrigins, 저장 출처는 빈 집합이다.

    2. COS 레지스트리[hash]를 entry설정한다.

  4. handlerealm에서 교차 출처 저장소 파일 시스템 내부의 entry를 가리키는 로케이터를 가진 FileSystemFileHandle을 생성한 결과로 둔다 [FS].

  5. handle요청된 출처requestedOrigins로 설정한다.

    참고: entry가 이미 존재했는지, 이미 "written"인지와 관계없이 handle을 반환한다. 호출자는 여전히 handle을 통해 전체 파일 바이트를 제공해야 한다. 따라서 쓰기를 이전 존재 여부를 감지하는 데 사용할 수 없으며(§ 7.2 교차 사이트 탐색 참조), 더 허용적인 출처 값에 대한 요청을 승인하기 전에 검증할 수 있다. § 3.4 리소스 가시성 상향을 참조한다.

  6. global이 주어졌을 때 DOM 조작 태스크 소스전역 태스크를 대기열에 추가하여 resulthandle이행한다.

(DOMString or sequence<DOMString>) 또는 undefined인 origins가 주어졌을 때 요청된 출처를 정규화하려면 "*", 출처목록 또는 null을 반환한다.
  1. origins존재하지 않으면 null을 반환한다.

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

  3. list를 « »로 둔다.

  4. origins의 각 candidate에 대해 반복한다. 하나의 문자열은 항목 하나의 목록으로 취급한다.

    1. candidateOrigincandidate기본 URL 파서를 실행한 결과인 출처로 둔다.

      참고: COS 요청 검증에서 각 candidate가 불투명하지 않은 출처로 파싱됨을 이미 확인했다.

    2. listcandidateOrigin포함하지 않으면 candidateOriginlist추가한다.

  5. list를 반환한다.

참고: 나중에 기존 항목으로 병합할 때만 중복을 제거하는 대신 여기에서 중복을 제거하면, 항목이 처음 생성되는 순간부터 출처에 중복이 없게 된다. 따라서 이후 만들어지는 모든 복제본에도 중복이 없다.

COS 항목을 가리키는 로케이터를 가진 핸들에서 createWritable()을 호출하여 얻은 FileSystemWritableFileStream이 닫히면 [FS], 사용자 에이전트는 해당 닫기 연산의 프로미스가 이행되기 전에 아래의 검증 및 저장 단계를 실행해야 한다.

참고: 이는 명시적인 close() 호출 또는 소스 끝에 도달하여 기본적으로 대상도 닫는 pipeTo() 호출 등 닫기가 어떤 방식으로 시작되었는지와 관계없이 적용된다. [STREAMS]는 스트림이 닫히는 시점에 두 경우를 구분하지 않으며, 이 알고리즘도 구분하지 않는다.

닫힌 스트림의 핸들이 가리키는 COS 항목 entry, 작성이 완료된 바이트 시퀀스 bytes, 닫기 연산의 관련 설정 객체출처 origin이 주어졌을 때 검증 및 저장 단계는 다음과 같다.
  1. computedValue[WEBCRYPTO]에 따라 entry알고리즘이 지정하는 알고리즘을 사용해 계산한 bytes의 소문자 16진수 다이제스트로 둔다.

  2. computedValueentry과 정확히 같지 않으면:

    1. 닫기 연산의 프로미스를 "DataError" DOMException으로 거부하고, entry는 수정하지 않는다.

    2. 이 단계를 중단한다.

  3. 다음 단계를 교차 출처 저장소 큐대기열에 추가한다.

    1. entry바이트bytes로 설정한다.

    2. entry상태를 "written"으로 설정한다.

    3. 아직 존재하지 않는 경우 originentry저장 출처추가한다.

    4. entry와 핸들의 요청된 출처가 주어졌을 때 리소스 가시성 상향을 실행한다.

파일 시스템 표준 [FS]은 종속 명세가 FileSystemWritableFileStream의 닫기 단계에 쓰기별 추가 검증을 연결할 수 있는 확장 지점을 아직 정의하지 않는다. 이러한 연결 지점이 생길 때까지 이 절에서는 필요한 동작을 직접 설명한다. 향후 개정에서는 [FS]와 정식으로 통합할 것으로 예상된다.

3.4. 리소스 가시성 상향

COS 항목의 가시성은 상향할 수 있지만 하향할 수는 없다.

COS 항목 entry와 "*", 출처목록 또는 null인 requestedOrigins가 주어졌을 때 리소스 가시성을 상향하려면:
  1. requestedOrigins가 null이면 반환한다.

    참고: origins를 생략해도 기존 항목의 범위는 축소되지 않는다. 생략은 동일 사이트 가용성만 요청하며, 모든 항목은 이미 적어도 그만큼의 가용성을 가진다.

  2. entry출처가 "*"이면 반환한다.

    참고: 이미 전역으로 사용 가능한 항목을 나중의 작성자가 제한할 수는 없다. 이 참고가 적용되고 requestedOrigins가 "*"가 아니면 사용자 에이전트는 요청된 제한이 적용되지 않았음을 개발자에게 알리는 콘솔 경고를 기록할 것으로 예상된다.

  3. requestedOrigins가 "*"이면:

    1. entry출처를 "*"로 설정한다.

    2. 반환한다.

  4. entry출처가 null이면:

    1. entry출처requestedOrigins로 설정한다.

    2. 반환한다.

  5. mergedentry출처복제본으로 둔다.

  6. requestedOrigins의 각 candidateOrigin에 대해 반복한다.

    1. mergedcandidateOrigin포함하면 계속한다.

    2. merged크기가 사용자 에이전트의 최대 출처 목록 길이와 같으면 중단한다.

      참고: 나머지 candidateOrigin 값은 쓰기 자체가 이미 성공했으므로 상향을 실패시키는 대신 이 상향에서 조용히 제외된다. 다만 사용자 에이전트는 항목의 출처 목록이 최대 용량에 도달했다는 콘솔 경고를 기록할 것으로 예상된다.

    3. candidateOriginmerged추가한다.

  7. entry출처merged로 설정한다.

참고: 원래 저장자뿐 아니라 새 사이트도 항목의 출처 범위를 넓힐 수 있다. 단, 항목의 해시가 되는 바이트도 함께 제공해야 한다. 이는 의도된 동작이다. 어떤 사이트든 해당 해시에 맞는 올바른 바이트를 이미 가지고 있다면, 그 해시가 무엇을 나타내는지에 대해 구조적으로 원래 저장자와 동일한 권위를 가진다.

3.4.1. 원래 저장자의 접근

COS 항목쓰기를 성공적으로 완료한 출처, 즉 항목의 저장 출처에 포함된 모든 출처는 이후 언제든 requestFileHandle()을 통해 해당 항목의 핸들을 얻을 수 있다. 이는 항목의 출처 값 및 항목의 해시PHL에 있는지와 무관하다. 이는 출처가 자신이 저장한 항목에 항상 접근할 수 있는 Cache API의 모델을 따른다.

4. 교차 출처 저장소 파일 시스템

교차 출처 저장소 파일 시스템은 출처의 버킷 파일 시스템 또는 로컬 파일 시스템 접근 루트와 구별되는 파일 시스템 루트이다. 이 시스템의 항목COS 레지스트리COS 항목과 일대일로 대응한다.

교차 출처 저장소 파일 시스템[FS]의 일반적인 호출별 권한 검사 모델을 사용하지 않는다. 이 시스템에서 얻은 모든 FileSystemFileHandle은 스크립트에 반환되기 전에 이미 § 3.2 파일 읽기 또는 § 3.3 파일 생성 및 쓰기를 통해 완전히 승인되었다. 따라서 이러한 핸들에서 getFile() 또는 createWritable()을 호출해도 추가 권한 프롬프트가 표시되지 않는다.

COS 항목 entry를 가리키는 FileSystemFileHandleentry상태가 아직 "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 교차 사이트 탐색을 참조한다.

두 호출은 연산의 매우 다른 시점에 발생하므로, 이 제한을 초과한 경우 각 위치에서 다르게 처리한다.

5.2. 축출

이 절은 비규범적이다.

저장 공간이 부족하면 사용자 에이전트는 COS 레지스트리에서 항목을 축출할 수 있다. 예를 들어 각 항목에 가장 최근 접근한 저장 출처 전체를 기준으로 가장 오래 사용되지 않은 항목을 우선하는 정책을 사용할 수 있다. 사용자 에이전트는 사용자가 저장된 파일, 각 파일에 접근한 출처를 확인하고, 항목을 수동으로 삭제하거나 모든 교차 출처 저장소 데이터를 지울 수 있는 설정 UI를 제공할 것으로 예상된다.

사용자가 출처의 사이트 데이터를 지우면 사용자 에이전트는 해당 출처가 포함된 모든 저장 출처 집합에서 해당 출처를 제거하는 것이 좋다. 제거한 뒤 COS 항목저장 출처가 비어 있으면 사용자 에이전트는 해당 항목의 삭제를 고려할 수 있다.

5.3. 수동으로 추가된 항목

이 절은 비규범적이다.

위에서 설명한 설정 UI를 통해 사용자는 디스크에 이미 보유한 파일을 교차 출처 저장소에 직접 추가할 수 있다. 예를 들어 웹사이트와 무관하게 다운로드한 AI 모델이며, 스크립트에서 requestFileHandle()을 호출하지 않아도 된다. 이러한 항목에는 쓰기를 귀속할 요청 출처가 없으므로, 명령형 API만으로는 답할 수 없는 두 가지 문제가 생긴다.

이 방식으로 추가된 뒤 상태가 "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()이 존재 여부를 알아내는 메커니즘이므로 각 호출은 사실상 탐색이다. 이 명세의 두 독립적인 메커니즘은 탐색으로 알아낼 수 있는 정보를 제한한다.

첫 번째 항목은 "선택한 출처 집합"이 웹 전체보다 의미 있게 작게 유지되는 경우에만 성립한다. 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 항목, 가용성 게이팅, 공개 해시 목록만 정의한다.

설명 목적으로만, 다음은 동일한 전역 공유 리소스를 세 가지 형식으로 교차 출처 저장소에 사용하도록 선택하는 예이다.

<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(*));
}

이 코드 조각은 설명용일 뿐이다. 이 구문은 이 명세에서 정의하지 않으며, 제한된 비-"*" 출처 값을 표기하는 방법을 포함한 각 형식의 권위 있는 문법은 이 문서가 아니라 자체 호스트 언어 명세에 속한다.

세 형식 모두 네트워크 가져오기로 대체하기 전에 일치하며 공개 가능한 항목이 있는지 COS 레지스트리를 먼저 확인하고, 성공적으로 가져와 무결성이 검증된 리소스를 다른 출처에서 재사용하도록 COS 레지스트리에 저장하는 처리 모델을 공유할 것으로 예상된다. 이는 requestFileHandle()과 정확히 같다. 이러한 통합에 관한 논의는 이 저장소의 이슈 추적기가 아니라 해당 통합을 포함할 호스트 언어 명세의 추적기에서 이루어져야 한다.

감사의 말

귀중한 피드백을 제공한 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/
[FileAPI]
Marijn Kruisselbrink. 파일 API. URL: https://w3c.github.io/FileAPI/
[FS]
Austin Sullivan. 파일 시스템 표준. 현행 표준. URL: https://fs.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. 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. 웹 암호화 레벨 2. URL: https://w3c.github.io/webcrypto/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 표준. 현행 표준. URL: https://webidl.spec.whatwg.org/

비규범적 참고문헌

[SRI]
Frederik Braun. 하위 리소스 무결성. URL: https://w3c.github.io/webappsec-subresource-integrity/
[STREAMS]
Adam Rice; et al. 스트림 표준. 현행 표준. URL: https://streams.spec.whatwg.org/
[UA-CLIENT-HINTS]
사용자 에이전트 클라이언트 힌트. 커뮤니티 그룹 보고서 초안. 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] 표준의 공개 접미사 목록이 규범적인 문구가 아니라 동반 데이터 파일인 방식과 같은 취지로 상세히 설계되었다 — 이 저장소의 Public Hash List 설명서를 참조하라. 이 설계는 WHATWG에 의한 거버넌스를 제안하며, 공개 접미사 목록의 공급업체 간 협력, 롤링 릴리스 선례를 모델로 삼고, 독립적으로 입증된 보편성에 기반한 승인 기준을 사용한다 — 이는 위에서 설명한 k-익명성 스타일 기준의 구체적인 사례이며, 사용자 에이전트가 쿼리마다 반복하는 검사가 아니라 해시가 승인되는 방식의 일부로 오프라인에서 한 번 적용된다. 이러한 내용은 아직 이 제안 외부에서는 확립되지 않았다. 목록 자체에 대한 초기 비규범적 코드 프로토타입은 이 저장소의 public-hash-list/implementation/에서 유지 관리된다 — 실용적인 임시 위치이며, 전용 공급업체 간 저장소는 PHL 설명서에 설명된 거버넌스 목표로 남아 있다. 이 명세는 해시가 PHL에 있는지에만 의존하며, 특정 검색 메커니즘이나 거버넌스 모델에는 의존하지 않는다. 따라서 해당 설계가 어떻게 발전하더라도 올바른 상태로 유지된다.
File System Standard [FS]는 아직 종속 명세가 FileSystemWritableFileStream의 닫기 단계에 추가적인 쓰기별 유효성 검사를 연결할 수 있는 확장 지점을 정의하지 않는다. 이러한 연결 지점이 존재할 때까지 이 절에서는 필요한 동작을 직접 설명한다. 향후 개정에서는 [FS]와 공식적으로 통합될 예정이다.