Copyright © 2026 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
이 명세는 HTMLMediaElement [HTML]을
확장하여 암호화된 콘텐츠의 재생을 제어하는 API를
제공한다.
이 API는 단순한 클리어 키 복호화부터 고부가가치 비디오까지 (적절한 사용자 에이전트 구현이 주어진 경우) 다양한 사용 사례를 지원한다. 라이선스/키 교환은 애플리케이션이 제어하며, 다양한 콘텐츠 복호화 및 보호 기술을 지원하는 견고한 재생 애플리케이션의 개발을 촉진한다.
이 명세는 콘텐츠 보호 또는 디지털 저작권 관리 시스템을 정의하지 않는다. 그 대신 이러한 시스템 및 더 단순한 콘텐츠 암호화 시스템을 발견하고, 선택하고, 상호작용하는 데 사용할 수 있는 공통 API를 정의한다. 이 명세를 준수하기 위해 디지털 저작권 관리를 구현할 필요는 없다. 공통 기준선으로 구현이 요구되는 것은 Clear Key 시스템뿐이다.
공통 API는 단순한 콘텐츠 암호화 기능 집합을 지원하며, 인증 및 권한 부여와 같은 애플리케이션 기능은 페이지 작성자에게 맡긴다. 이는 암호화 시스템과 라이선스 또는 기타 서버 간의 대역 외 통신을 가정하는 대신, 콘텐츠 보호 시스템별 메시징을 페이지가 중개하도록 요구함으로써 달성된다.
이 절은 이 문서가 발행된 시점의 상태를 설명한다. 현재 W3C 발행물 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 색인에서 확인할 수 있다.
2017년 9월에 W3C 권고안으로 발행된 이후 두 가지 새 기능이 추가되었다:
encryptionScheme
특성을 통한 암호화 스킴 기능 감지.
getStatusForPolicy()
메서드를 통해 HDCP 정책과 연결된 키의 상태를 질의하는 기능.
다른 기능의 포함은 Media Working Group의 범위를 벗어난다. 편집상의 업데이트에 더하여, 이 명세에 가해진 다른 실질적 변경은 이 명세에 대한 유지보수 이슈를 다룬다:
encrypted-media 식별자를 통해
Permissions Policy와 통합한다.
MediaKeyStatus에 "usable-in-future"를 추가한다.
QuotaExceededError를 반환한다.
MediaKeySessionClosedReason를
추가하고,
그에 맞게 알고리즘을 조정한다.
이전 버전 이후 이루어진 변경의 전체 목록은 커밋을 참고한다.
이 문서는 Media Working Group이 권고안 트랙을 사용하여 작업 초안으로 발행했다.
작업 초안으로 발행되었다는 사실이 W3C와 그 회원의 승인을 의미하지는 않는다.
이 문서는 초안 문서이며 언제든지 다른 문서로 업데이트, 대체 또는 폐기될 수 있다. 진행 중인 작업 이외의 것으로 이 문서를 인용하는 것은 부적절하다.
이 문서는 W3C 특허 정책에 따라 운영되는 그룹이 작성했다. W3C는 이 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지한다. 해당 페이지에는 특허를 공개하기 위한 지침도 포함되어 있다. 어떤 개인이 필수 청구항을 포함한다고 믿는 특허를 실제로 알고 있는 경우, 그 개인은 W3C 특허 정책 6절에 따라 그 정보를 공개해야 한다.
이 문서는 2025년 8월 18일 W3C Process Document의 적용을 받는다.
이 절은 비규범적이다.
이 명세는 스크립트가 콘텐츠 보호 메커니즘을 선택하고, 라이선스/키 교환을 제어하며, 사용자 정의 라이선스 관리 알고리즘을 실행할 수 있게 한다. 각 사용 사례마다 각 사용자 에이전트에서 클라이언트 측 수정을 요구하지 않고도 광범위한 사용 사례를 지원한다. 이를 통해 콘텐츠 제공자는 모든 기기에 대한 단일 애플리케이션 솔루션을 개발할 수 있다.
지원되는 콘텐츠는 컨테이너별 "공통 암호화" 명세에 따라 암호화되며,
키 시스템 전반에서 사용할 수 있게 한다. 지원되는 콘텐츠는 암호화되지 않은 컨테이너를 가지므로,
메타데이터를 애플리케이션에 제공할 수 있고 다른
HTMLMediaElement 기능과의 호환성을 유지할 수 있다.
구현자는 이 명세에서 설명하는 보안 및 개인정보 보호 위협과 우려 사항에 대한 완화책에 주의를 기울여야 한다. 특히 보안 및 개인정보 보호에 대한 명세 요구사항은 키 시스템과 그 구현의 보안 및 개인정보 보호 속성을 알지 못하면 충족할 수 없다. 8. 구현 요구사항에는 기반 키 시스템 구현의 통합 및 사용과 관련된 보안 및 개인정보 보호 조항이 포함되어 있다. 10. 보안은 입력 데이터 또는 네트워크 공격과 같은 외부 위협에 초점을 맞춘다. 11. 개인정보 보호는 사용자별 정보의 처리와 사용자에게 자신의 개인정보에 대한 충분한 제어를 제공하는 데 초점을 맞춘다.
이 명세는 미디어 데이터의 출처와 독립적이지만, 작성자는 많은 구현이 Media Source Extensions [MEDIA-SOURCE]를 통해 제공되는 미디어 데이터의 복호화만 지원한다는 점을 알고 있어야 한다.
API를 사용하여 구현된 일반적인 스택이 아래에 표시되어 있다. 이 다이어그램은 예시 흐름을 보여 주며, API 호출과 이벤트의 다른 조합도 가능하다.
콘텐츠 복호화 모듈(CDM)은 하나 이상의 키 시스템에 대해 복호화를 포함한 기능을 제공하는 클라이언트 구성요소이다.
구현은 CDM의 구현을 분리할 수도 있고 분리하지 않을 수도 있으며, 사용자 에이전트와 별개로 취급할 수도 있다. 이는 API와 애플리케이션에 투명하다.
키 시스템은 복호화 메커니즘 및/또는 콘텐츠 보호 제공자를 가리키는 일반 용어이다. 키 시스템 문자열은 키 시스템의 고유한 식별을 제공한다. 이 문자열은 사용자 에이전트가 CDM을 선택하고 키 관련 이벤트의 출처를 식별하는 데 사용된다. 사용자 에이전트는 공통 키 시스템을 지원해야 MUST 한다. 사용자 에이전트는 해당 키 시스템 문자열과 함께 추가적인 CDM도 제공할 수 MAY 있다.
키 시스템 문자열은 항상 역방향 도메인 이름이다. 키 시스템 문자열은 대소문자를 구분하여 비교된다. CDM은 단순한 소문자 ASCII 키 시스템 문자열을 사용하는 것이 권장된다 RECOMMENDED.
예를 들어, "com.example.somesystem".
주어진 시스템(예시의 "somesystem") 내에서 하위 시스템은 키 시스템 제공자가 결정한 대로 정의될 수 있다. 예를 들어, "com.example.somesystem.1" 및 "com.example.somesystem.1_5". 키 시스템 제공자는 이 문자열들이 비교 및 발견에 사용된다는 점을 염두에 두어야 하므로, 비교하기 쉬워야 하며 구조는 합리적으로 단순하게 유지되어야 한다.
키 세션, 또는 단순히 세션은 CDM과의 메시지 교환을 위한 컨텍스트를 제공하며,
그 결과 키가 CDM에 제공된다. 세션은
MediaKeySession 객체로
구체화된다. 각 키 세션은
generateRequest()
호출에 제공된 단일 초기화 데이터 인스턴스와 연결된다.
각 키 세션은 단일 MediaKeys 객체와 연결되며, 해당
MediaKeys 객체와 연결된
미디어 요소만 세션과 연결된 키에 접근할 수 있다. 다른
MediaKeys 객체,
CDM 인스턴스 및 미디어 요소는 키 세션에 접근하거나
그 키를 사용해서는 안 된다 MUST NOT. 키 세션과 그 안에 포함된 키는
MediaKeySession 객체가
파괴되는 경우를 포함하여 세션이 닫히면 더 이상 복호화에 사용할 수 없다.
키 세션과 연결되어 있고 명시적으로 저장되지 않은 모든 라이선스와 키는 키 세션이 닫힐 때 파괴되어야 MUST 한다.
키 ID는 세션 내에서 고유해야 MUST 한다.
세션 ID는 CDM이 생성한 고유 문자열
식별자로, 애플리케이션이 MediaKeySession 객체를 식별하는
데 사용할 수 있다.
사용자 에이전트와 CDM이 새 세션을 성공적으로 생성할 때마다 새 세션 ID가 생성된다.
각 세션 ID는 그것이 생성된 브라우징 컨텍스트 내에서 고유해야
SHALL 한다.
영속 세션 타입인가? 알고리즘이
true를 반환하는 세션 타입의 경우, 세션 ID는 브라우징 세션 전반을 포함하여
시간에 따라 출처 내에서
고유해야 MUST 한다.
기반 콘텐츠 보호 프로토콜이 반드시 세션 ID를 지원할 필요는 없다.
달리 명시되지 않는 한, 키는 미디어 데이터 내의
블록을 복호화하는 데 사용할 수 있는 복호화 키를 가리킨다. 이러한 각 키는
키 ID에 의해 고유하게 식별된다. 키는 그것을
CDM에 제공하는 데 사용된
세션과 연결된다. (같은 키가
여러 세션에 존재할 수 있다.) 이러한 키는
update() 호출을 통해서만
CDM에 제공되어야 MUST 한다. (이후에는
저장된 세션 데이터의 일부로 load()에
의해 로드될 수 있다.)
예를 들어, 두 비디오 해상도 사이에 정책이 다른 경우 각 스트림 집합은 고유한 키로 암호화되므로 정책을 독립적으로 적용할 수 있다. 마찬가지로, 오디오 스트림과 비디오 스트림은 정책이 서로 다를 때 고유한 키를 사용한다. 정책 그룹 간에 키를 공유하면 독립적인 적용이 불가능해지므로, 정책 그룹별 고유 키는 클라이언트 전반에서 적용과 호환성을 보장하는 유일한 방법이다.
CDM이 해당 키가 현재 미디어 데이터의 하나 이상의 블록을 복호화하는 데 사용할 수 있다고 확신하는 경우, 키는 복호화에 사용할 수 있는 것으로 간주된다.
예를 들어, 라이선스가 만료된 경우 키는 복호화에 사용할 수 없다. 라이선스가 만료되지 않았더라도, 키 사용을 위한 다른 조건(예: 출력 보호)이 현재 충족되지 않으면 키는 복호화에 사용할 수 없다.
키는 옥텟 시퀀스이며 해당 키를 고유하게 식별하는 키 ID와 연결된다. 컨테이너는 미디어 데이터 안의 블록 또는 블록 집합을 복호화할 수 있는 키의 ID를 지정한다. 초기화 데이터에는 미디어 데이터를 복호화하는 데 필요한 키를 식별하기 위한 키 ID가 포함될 MAY 있다. 그러나 초기화 데이터가 미디어 데이터 또는 미디어 리소스에서 사용되는 일부 또는 모든 키 ID를 포함해야 한다는 요구사항은 없다. 라이선스가 CDM에 제공될 때 각 키를 키 ID와 연결하므로, CDM은 암호화된 미디어 데이터 블록을 복호화할 때 적절한 키를 선택할 수 있다.
CDM의 세션 구현이 실제 키가 사용 가능하거나 그 값을 알고 있는지와 관계없이,
해당 키에 관한 정보, 특히 키
ID를 포함하는 경우, 키는 세션에 알려진 것으로 간주된다. 알려진 키는
keyStatuses 속성을 통해 노출된다.
키는 만료로 인해 사용할 수 없게 되거나, 제거되었지만 라이선스 폐기 기록을 사용할 수 있는 경우처럼, 사용할 수 없게 된 뒤에도 알려진 것으로 간주된다. 키는 세션에서 명시적으로 제거되고 모든 라이선스 해제 메시지가 확인된 경우에만 알 수 없는 상태가 된다.
예를 들어, update() 호출이
해당 키를 포함하지 않고 이전에 그 키를 포함했던 라이선스를 대체하라는 지시를 포함하는
새 라이선스를 제공하는 경우, 키는 알 수 없는 상태가 될 수 있다.
라이선스는 하나 이상의 키를 포함하는 키 시스템별 상태 정보이며, 각 키는 키 ID와 연결되고, 키 사용에 관한 다른 정보를 잠재적으로 포함한다.
키 시스템은 보통 라이선스 요청 메시지를 구성하기 전에 복호화할 스트림에 관한 정보를 포함하는 초기화 데이터 블록을 필요로 한다. 이 블록은 단순한 키 또는 콘텐츠 ID일 수도 있고, 그러한 정보를 포함하는 더 복잡한 구조일 수도 있다. 애플리케이션은 초기화 데이터를 어떤 애플리케이션별 방식으로 얻거나 미디어 데이터에서 얻는다.
초기화 데이터는 라이선스 요청을 생성하기 위해 CDM이 사용하는 컨테이너별 데이터를 가리키는 일반적인 용어이다.
초기화 데이터의 형식은 컨테이너의 유형에 따라 달라지며, 컨테이너는 둘 이상의 초기화 데이터 형식을 지원할 MAY 있다. 초기화 데이터 유형은 함께 제공되는 초기화 데이터의 형식을 나타내는 문자열이다. 초기화 데이터 유형 문자열은 항상 대소문자를 구분하여 일치된다. 초기화 데이터 유형 문자열은 소문자 ASCII 문자열일 것이 RECOMMENDED 된다.
암호화된 미디어 확장 초기화 데이터 형식 레지스트리는 초기화 데이터 유형 문자열에서 각 형식의 명세로의 매핑을 제공한다.
사용자 에이전트가 미디어 데이터에서 초기화 데이터를 만나면,
그 초기화 데이터를
initData 속성에 넣어
이벤트를 통해 애플리케이션에 제공한다. 사용자
에이전트는
초기화 데이터를 저장하거나 그 시점에 그 내용을 사용해서는 MUST NOT 된다.
애플리케이션은 초기화 데이터를
CDM에
encryptedgenerateRequest()를
통해 제공한다.
사용자 에이전트는 초기화 데이터를 다른 수단으로
CDM에 제공해서는 MUST NOT 된다.
초기화 데이터는 주어진 스트림 집합 또는 미디어 데이터에 대해 고정된 값이어야 MUST 한다. 이는 주어진 스트림 집합 또는 미디어 데이터를 재생하는 데 필요한 키와 관련된 정보만 포함해야 MUST 한다. 이는 애플리케이션 데이터, 클라이언트별 데이터, 사용자별 데이터 또는 실행 가능한 코드를 포함해서는 MUST NOT 된다.
초기화 데이터는 키 시스템별 데이터 또는 값을 포함하지 않는 것이 SHOULD NOT 된다. 구현은 지원하는 각 초기화 데이터 유형에 대해 [EME-INITDATA-REGISTRY]에 정의된 공통 형식을 지원해야 MUST 한다.
독점 형식/콘텐츠의 사용은 권장되지 않으며, 독점 형식만 지원하거나 사용하는 것은 강하게 권장되지 않는다. 독점 형식은 기존 콘텐츠 또는 공통 형식을 지원하지 않는 기존 클라이언트 장치에서만 사용해야 한다.
둘 이상의 식별자 또는 다른 값이 동일하거나 또는 합리적인 시간과 노력으로 상호 관련시키거나 연관시킬 수 있는 경우, 그 값들은 연관 가능하다고 한다. 그렇지 않으면 그 값들은 연관 불가능하다.
둘 이상의 식별자 또는 다른 값이, 참조되는 엔터티 또는 엔터티 집합이 추가 엔터티의 참여 없이 합리적인 시간과 노력으로 이를 상호 관련시키거나 연관시킬 수 있는 경우 엔터티에 의해 연관 가능하다고 한다. 그렇지 않으면 그 값들은 엔터티에 의해 연관 불가능하다.
둘 이상의 식별자 또는 다른 값이, 해당 엔터티가 애플리케이션, 모든 다른 애플리케이션, 그리고 이들이 사용하거나 통신하는 서버 같은 다른 엔터티를 포함하는 집합인 경우 엔터티에 의해 연관 불가능하다면 애플리케이션에 의해 연관 불가능하다고 한다. 그렇지 않으면 그 값들은 애플리케이션에 의해 연관 가능한 것으로 간주되며, 이는 금지된다.
고유 식별성 값은 값, 데이터 조각, 데이터 조각의 소유에서 비롯되는 함의, 또는 대규모 사용자 또는 클라이언트 장치 집단에 공유되지 않는 관찰 가능한 동작이나 타이밍이다. 고유 식별성 값은 메모리에 있거나 지속될 수 있다.
고유 식별성 값은 일반적으로 사용자 또는 클라이언트 장치에 대해 고유하지만, 고유 식별성을 갖기 위해 반드시 엄격하게 고유할 필요는 없다. 예를 들어, 소수의 사용자 사이에서 공유되는 값도 여전히 고유 식별성을 가질 수 있다.
영구 식별자는 어떤 방식으로든 지워지지 않거나, 사용자가 제거, 재설정 또는 변경하기에 사소하지 않은 값, 데이터 조각, 데이터 조각의 소유에서 비롯되는 함의, 또는 관찰 가능한 동작이나 타이밍이다. 여기에는 다음이 포함되지만 이에 한정되지 않는다.
하드웨어 또는 하드웨어 기반 식별자
공장에서 하드웨어 장치에 프로비저닝된 값
운영체제 설치 인스턴스와 연결되었거나 여기서 파생된 값
사용자 에이전트 설치 인스턴스와 연결되었거나 여기서 파생된 값
CDM 또는 다른 소프트웨어 구성요소와 연결되었거나 여기서 파생된 값
클라이언트에서 생성되었더라도 구성 파일 또는 이와 유사한 반영구 데이터에 있는 값
클라이언트 또는 기타 사용자 계정 값
고유 영구 식별자는 영구 식별자이면서 고유 식별성을 갖는 것이다.
클라이언트 외부에 노출될 때, 고유 영구 식별자 및 그로부터 파생되었거나 그와 관련된 값은 암호화되어야 MUST 한다. 고유 영구 식별자는 암호화된 형태로라도 애플리케이션에 노출되어서는 결코 MUST NOT 된다.
고유 영구 식별자는 일반적으로 사용자 또는 클라이언트 장치에 대해 고유하지만, 고유 식별성을 갖기 위해 반드시 엄격하게 고유할 필요는 없다. 예를 들어, 소수의 사용자 사이에서 공유되는 고유 영구 식별자도 여전히 고유 식별성을 가질 수 있다.
고유 영구 식별자는 이 명세의 범위 안에서 파생되거나 생성되지 않았기 때문에 아니다 고유 식별자가 아니다.
distinctiveIdentifier는
고유 영구 식별자를 사용할 수 있는지 제어한다. 구체적으로, 고유 영구 식별자는
distinctiveIdentifier
멤버의 값이, MediaKeySystemAccess를 사용해 생성한
MediaKeys 객체에서
"required"일 때만 사용할 수 있다.
고유 식별자는 불투명하거나 암호화된 형태를 포함하는 값으로, 클라이언트 외부의 어떤 엔터티가 웹 플랫폼에서 사용자가 예상할 수 있는 범위(예: 쿠키 및 기타 사이트 데이터)를 넘어 값을 상호 관련시키거나 연관시킬 수 있는 값이다. 예를 들어, 사용자가 브라우징 데이터를 지운 뒤에도, 또는 사용자가 그러한 연관을 끊기 쉽지 않은 값에 대해 자신의 개인정보를 보호하려고 시도한 뒤에도, a) 출처, b) 브라우징 프로필, 또는 c) 브라우징 세션 전반에서 애플리케이션이 아닌 엔터티에 의해 연관 가능한 값이 이에 해당한다. 특히, 개별화 요청에 공통 값이 포함되어 있었거나, 개별화 요청에서 제공된 값이 브라우징 데이터 삭제 시도 이후에도 개별화 서버 같은 중앙 서버가 연관시킬 수 있기 때문에, 출처 전반에서 값을 연관시킬 수 있는 경우 그 값은 고유 식별자이다. 이러한 원인에는 개별화 과정에서 고유 영구 식별자를 사용하는 것이 포함될 수 있다.
암호화된 형태로라도 애플리케이션에 노출되는 고유 식별자는 식별자 요구사항의 적용을 받으며, 여기에는 암호화, 출처 및 프로필별 고유성, 그리고 삭제 가능성이 포함된다.
고유 식별자의 인스턴스화 또는 사용은 이 명세에 정의된 API를 애플리케이션이 사용하는 것에 의해 트리거되지만, 고유 식별자와 관련된 조건을 트리거하기 위해 그 식별자가 애플리케이션에 제공될 필요는 없다. (고유 영구 식별자는 불투명하거나 암호화된 형태로도 애플리케이션에 제공되지 않는다.)
distinctiveIdentifier는
고유 식별자를 사용할 수 있는지 제어한다. 구체적으로, 고유 식별자는
distinctiveIdentifier
멤버의 값이, MediaKeySystemAccess를 사용해 생성한
MediaKeys 객체에서
"required"일 때만 사용할 수 있다.
고유 식별자는 다음 기준을 모두 충족하는 값, 데이터 조각, 데이터 조각의 소유에서 비롯되는 함의, 또는 관찰 가능한 동작이나 타이밍이다.
이는 고유 식별성을 가진다.
고유 식별자는 일반적으로 사용자 또는 클라이언트 장치에 대해 고유하지만, 식별자가 고유 식별성을 갖기 위해 반드시 엄격하게 고유할 필요는 없다. 예를 들어, 소수의 사용자 사이에서 공유되는 식별자도 여전히 고유 식별성을 가질 수 있다.
그것, 그것에 관한 정보, 또는 그것에서 파생되었거나 그와 관련된 값이 암호화된 형태로라도 클라이언트 외부에 노출된다. 여기에는 애플리케이션 및/또는 라이선스, 개별화, 또는 다른 서버에 이를 제공하는 것이 포함되지만 이에 한정되지 않는다.
이는 다음 속성 중 하나 이상을 가진다.
하나 이상의 고유 영구 식별자에서 파생된다.
그 값을 생성한 생성, 개별화, 프로비저닝 또는 다른 과정이 하나 이상의 고유 영구 식별자 또는 다른 고유 식별자를 관련시키거나, 사용하거나, 제공하거나, 그로부터 파생되었거나, 유사하게 관련시켰다.
이는 삭제 가능하지만 쿠키 및 기타 사이트 데이터와 함께 삭제 가능하지는 않다.
예를 들어, 운영체제 수준 메커니즘처럼 사용자 에이전트 외부의 어떤 메커니즘을 통하는 경우이다.
애플리케이션에 노출되는 값에 대해 규범적으로 금지되는 기타 우려 속성에는 다음이 포함된다.
이는 고유 영구 식별자이다.
이는 삭제 가능하지 않다.
식별자 삭제 후 생성된 값은 이전 값과 애플리케이션에 의해 연관 가능할 수 있다.
값이 출처 및 프로필별 고유하지 않을 수 있다.
서로 다른 출처의 값이 애플리케이션에 의해 연관 가능할 수 있다.
그러한 규범적으로 금지되는 값의 예에는 다음이 포함되지만 이에 한정되지 않는다.
모든 출처에 사용되는 단일 하드웨어 기반 값.
모든 출처에 사용되는 단일 무작위 기반 값.
모든 출처에 사용되는 개별화 과정에서 얻은 단일 값.
위 값 중 어느 하나의 전부 또는 일부를 포함하는 값.
여러 출처에 사용되지만 모든 출처에는 사용되지 않는 단일 값.
한 도메인의 모든 출처에 사용되는 단일 값. (식별자는 출처별이어야 한다.)
미리 프로비저닝된 출처별 값.
쉽게 되돌릴 수 있는 수단으로 생성되어, 클라이언트에서 생성되었는지 또는 개별화 과정이 관련되었는지와 관계없이 애플리케이션에 의해 연관 가능한 값. 예를 들어, 출처의 일부 또는 전부를 고정 값과 XOR하거나 다른 방식으로 통합하는 경우이다.
고유 식별자는 보통 이를 생성한 엔터티에 의해 연관 가능하지만, 이는 애플리케이션에 의해 연관 불가능해야 MUST 한다. 다시 말해, 그러한 상호 관련 또는 연관은 원래 고유 식별자 값을 생성한 개별화 서버 같은 엔터티에 의해서만 가능하다. 고유 영구 식별자에 접근할 수 있는 엔터티는 이 능력을 애플리케이션에 노출해서는 MUST NOT 된다. 그렇게 하면 결과적인 고유 식별자가 애플리케이션에 의해 연관 가능해지기 때문이다. 또한 그러한 상관관계가 다른 엔터티나 제3자에게 노출되지 않도록 주의해야 SHOULD 한다.
고유 식별자의 예에는 다음이 포함되지만 이에 한정되지 않는다.
키 요청에 포함되고, 다른 클라이언트 장치가 포함하는 바이트열과 다르며, 고유 영구 식별자를 사용해 직접 또는 간접적으로 기반하거나 취득된 바이트열.
키 요청에 포함되고, 다른 클라이언트 장치의 요청에 포함되는 공개 키와 다르며, 고유 영구 식별자를 사용해 직접 또는 간접적으로 기반하거나 취득된 공개 키.
다른 클라이언트 장치가 갖고 있지 않고, 고유 영구 식별자를 사용해 직접 또는 간접적으로 기반하거나 취득된 개인 키의 소유 증명(예: 어떤 데이터에 서명함으로써).
그러한 키에 대한 식별자.
첫 번째 값이 직접 노출되지 않더라도, 노출되는 다른 값을 파생하는 데 사용되는 그러한 값.
다른 고유 식별자에서 파생된 값.
고유 영구 식별자와 함께 (예: 개별화) 서버에 보고되었거나, 고유 영구 식별자를 제공한 후 그러한 서버가 제공한 무작위 값.
공장에서 하드웨어 장치에 프로비저닝된 고유 값에서 파생된 값.
공장에서 하드웨어 장치에 있는 고유 하드웨어 값(예: MAC 주소 또는 일련번호) 또는 소프트웨어 값(예: 운영체제 설치 인스턴스 또는 운영체제 사용자 계정 이름)에서 파생된 값.
고유 식별자가 아닌 것의 예:
설치 기반이 큰 경우, 주어진 CDM 버전의 모든 사본 사이에서 공유되는 공개 키.
고유하지만 하나의 세션에서만 사용되는 nonce 또는 임시 키.
개별화 또는 이와 유사한 것을 통해서도, 파생되거나 유사한 방식으로도 클라이언트 외부에 노출되지 않는 값.
예를 들어 비디오 파이프라인과 CDM 사이의 증명에 사용되는 장치 고유 키로서, CDM이 이러한 증명이 애플리케이션으로 더 흘러가도록 허용하지 않고, 대신 고유 식별자를 구성하지 않는 키를 사용해 자체적으로 새 증명을 만드는 경우.
쿠키 같은 브라우징 데이터와 함께 완전히 삭제/삭제 가능하며, 이후에는 연관 불가능한 값으로 대체되는 값] (단지 애플리케이션에 의해 연관 불가능한 것이 아니라), 개별화 서버 같은 중앙 서버에 의해서도 연관 불가능하며, 다음 중 하나 이상에 해당하는 경우:
값의 생성에 고유 영구 식별자 또는 고유 식별자가 관여하지 않았다.
시스템의 입력 없이 생성된 무작위 값이다.
다른 고유 식별자의 사용이나 지식 없이 서버가 제공한 값이다.
구현, 구성, 인스턴스 또는 객체가 그 수명 동안 또는 관련된 그러한 엔터티의 수명 동안 어느 시점에든, 하나 이상의 고유 식별자, 그에 관한 정보, 또는 그로부터 파생되었거나 그와 관련된 값을 암호화된 형태로라도 클라이언트 외부에 노출하는 경우, 그 구현, 구성, 인스턴스 또는 객체는 고유 식별자를 사용한다고 한다. 여기에는 그러한 값을 애플리케이션 및/또는 라이선스, 개별화, 또는 다른 서버에 제공하는 것이 포함되지만 이에 한정되지 않는다.
구현, 구성, 인스턴스 또는 객체가 그 수명 동안 또는 관련된 그러한 엔터티의 수명 동안 어느 시점에든, 하나 이상의 고유 영구 식별자, 그에 관한 정보, 또는 그로부터 파생되었거나 그와 관련된 값을 암호화된 형태로라도 클라이언트 외부에 노출하는 경우, 그 구현, 구성, 인스턴스 또는 객체는 고유 영구 식별자를 사용한다고 한다. 여기에는 그러한 값을 개별화 서버에 제공하는 것이 포함되지만 이에 한정되지 않는다. 그러한 값은 애플리케이션에 제공되어서는 MUST NOT 된다.
구현, 구성, 인스턴스 또는 객체가 고유 식별자를 사용하거나 및/또는 고유 영구 식별자를 사용하는 경우, 그 구현, 구성, 인스턴스 또는 객체는 고유 식별자 또는 고유 영구 식별자를 사용한다고 한다.
distinctiveIdentifier는
고유 식별자 및
고유
영구 식별자를 사용할 수 있는지 제어한다. 구체적으로, 그러한
식별자는 distinctiveIdentifier
멤버의 값이, MediaKeySystemAccess를 사용해 생성한
MediaKeys 객체에서
"required"일 때만 사용할 수 있다.
재생 중에, 임베드된 미디어 데이터는 임베딩하는 출처의 스크립트에 노출된다.
API가 초기화 데이터를
이벤트에서 제공하려면,
미디어
데이터가 임베딩 페이지와
CORS-same-origin이어야
MUST 한다.
미디어
데이터가 임베딩 문서와 교차 출처인 경우, 작성자는
encryptedHTMLMediaElement의
crossOrigin
속성과 미디어
데이터 응답의 CORS 헤더를 사용하여 이를
CORS-same-origin으로
만들어야 SHOULD 한다.
재생 중에, 임베드된 미디어 데이터는 임베딩하는 출처의 스크립트에 노출된다.
API가 초기화 데이터를
이벤트에서 제공하려면,
미디어
데이터는 혼합
콘텐츠 [MIXED-CONTENT]여서는 MUST NOT 된다.
encrypted
시간은 ECMAScript 언어 명세에 표현된 것과 동등해야 MUST 한다.
그러한 시간이 존재하지 않거나 시간이 불확정인 경우, 시간은 NaN과 같다.
시간은 결코 Infinity 값을 가져서는 안 된다.
시간은 일반적으로 밀리초 정확도의 한 시점을 나타내지만, 그것만으로는 충분한 정의가 아니다. 정의된 시간 값과 시간 범위 참조는 다른 중요한 요구사항을 추가한다.
그 이후에는 키가 더 이상 복호화에 사용 가능하지 않게 되는 시간.
주어진 머신의 사용자 에이전트는 애플리케이션에 보이는 상태와 데이터와 관련하여 독립적으로 동작할 것으로 기대되는 다양한 서로 다른 컨텍스트나 모드 또는 임시 상태에서의 실행을 지원할 수 있다. 특히, 저장된 모든 데이터는 독립적일 것으로 기대된다. 이 명세에서는 그러한 독립적인 컨텍스트나 모드를 "브라우징 프로필"이라고 한다.
그러한 독립적인 컨텍스트의 예에는, 사용자 에이전트가 서로 다른 운영체제 사용자 계정에서 실행되는 경우 또는 사용자 에이전트가 단일 계정에 대해 여러 독립 프로필을 정의하는 기능을 제공하는 경우가 포함된다.
이 절은 키 시스템에 대한 접근을 얻기 위한 메커니즘을 정의한다. 요청에 기능을 포함하는 것은 기능 감지도 가능하게 한다.
알고리즘의 단계는 프로미스를 거부할 때 항상 중단된다.
requestMediaKeySystemAccess()는
문자열
encrypted-media로
식별되는 정책 제어
기능이다.
그 기본
허용 목록은 'self'이다 [PERMISSIONS-POLICY].
WebIDLenum MediaKeysRequirement {
"required",
"optional",
"not-allowed"
};
MediaKeysRequirement 열거형은 다음과 같이 정의된다:
| 열거형 설명 | |
|---|---|
required
|
|
optional
|
|
not-allowed
|
|
WebIDLdictionary MediaKeySystemConfiguration {
DOMString label = "";
sequence<DOMString> initDataTypes = [];
sequence<MediaKeySystemMediaCapability> audioCapabilities = [];
sequence<MediaKeySystemMediaCapability> videoCapabilities = [];
MediaKeysRequirement distinctiveIdentifier = "optional";
MediaKeysRequirement persistentState = "optional";
sequence<DOMString> sessionTypes;
};
MediaKeySystemConfiguration
딕셔너리는 다음 멤버를 포함한다:
label
타입은 DOMString이며, 기본값은
""
MediaKeySystemConfiguration에
보존될 선택적 레이블이며,
getConfiguration()
메서드가
MediaKeySystemAccess에서 반환한다.
initDataTypes
타입은 sequence<DOMString>이며,
기본값은 []
audioCapabilities
타입은 sequence<MediaKeySystemMediaCapability>이며,
기본값은
[]
videoCapabilities
요소는 비어 있어서는 안 된다.
videoCapabilities
타입은 sequence<MediaKeySystemMediaCapability>이며,
기본값은
[]
audioCapabilities
요소는 비어 있어서는 안 된다.
distinctiveIdentifier
타입은 MediaKeysRequirement이며,
기본값은 "optional"
이 멤버가 "not-allowed"이면,
구현은 이 구성에서 생성된 어떤 객체와 연결된 어떤 작업에 대해서도
구별
식별자 또는 구별 영구 식별자를 사용해서는 안 된다
MUST NOT.
persistentState
타입은 MediaKeysRequirement이며, 기본값은
"optional"
이 멤버가
"not-allowed"이면,
CDM은 이 객체의
Document의
애플리케이션 또는
출처와 관련된
어떤 상태도 영속화해서는 안 된다 MUST NOT.
이 멤버의 목적상, 영속 상태에는 키 시스템
구현이 제어하는 영속 고유 식별자(구별
식별자)가 포함되지 않는다.
distinctiveIdentifier는
이 요구사항을 독립적으로 반영한다.
영속 상태가 지원되지 않는 경우에는
"temporary" 세션만
생성할 수 있다.
"temporary"가 아닌 세션을
생성하려는 애플리케이션은
requestMediaKeySystemAccess()를
호출할 때 이 멤버를 "required"로
설정해야 한다.
sessionTypes
타입은 sequence<DOMString>
MediaKeySessionType의
목록. 모든 값은 지원되어야 한다.
딕셔너리가
requestMediaKeySystemAccess()에
전달될 때 이 멤버가 존재하지 않으면 [Infra],
딕셔너리는 이 멤버가
[ "로 설정된 것처럼 취급된다.
temporary"
]
구현은 이 딕셔너리에 멤버를 추가해서는 안 된다 SHOULD NOT. 멤버가
추가되는 경우,
그것들은 MediaKeysRequirement
타입이어야
MUST 하며,
가장 넓은 범위의 애플리케이션 및 클라이언트 조합을 지원하기 위해 기본값을
"optional"로 가지는 것이
권장된다 RECOMMENDED.
사용자 에이전트 구현이 인식하지 않는 딕셔너리 멤버는
[WEBIDL]에 따라 무시되며,
requestMediaKeySystemAccess()
알고리즘에서 고려되지 않는다. 애플리케이션이 비표준 딕셔너리 멤버를 사용하는 경우,
그러한 딕셔너리 멤버가 포함된 구성을 사용자 에이전트 구현이 거부할 것이라고
의존해서는 안 된다 MUST
NOT.
이 딕셔너리는 상태 또는 데이터를 CDM에 전달하는 데 사용되어서는 안 된다 MUST NOT.
WebIDLdictionary MediaKeySystemMediaCapability {
DOMString contentType = "";
DOMString? encryptionScheme = null;
DOMString robustness = "";
};
MediaKeySystemMediaCapability
멤버
contentType
타입은 DOMString이며, 기본값은
""
encryptionScheme
타입은 DOMString이며, 기본값은
null
콘텐츠 타입과 연결된 암호화 스킴. null이거나 존재하지 않는 값은 애플리케이션이 특정 암호화 스킴을 요구하지 않으므로 어떤 암호화 스킴도 허용 가능하다는 것을 사용자 에이전트에 나타낸다.
빈 문자열은 null 또는 존재하지 않는 것과 구별되므로, 인식되지 않는 암호화 스킴으로 처리된다.
robustness
타입은 DOMString이며, 기본값은
""
콘텐츠 타입과 연결된 견고성 수준. 빈 문자열은 콘텐츠 타입을 복호화하고 디코딩할 수
있는 어떤 능력도 허용 가능함을 나타낸다.
구현은 CDM을, MediaKeySystemAccess 객체의
구성에 지정된 견고성 수준을 적어도 지원하도록 구성해야 MUST
하며, 이 객체는
MediaKeys 객체를
생성하는 데 사용된다.
이 객체가 나타내는 기능이 지원되는 것으로 간주되려면,
contentType은
빈 문자열이어서는 안 되며 MUST NOT, 모든 코덱을 포함한 전체 값이
robustness와 함께
지원되어야 MUST 한다.
코덱 집합 중 어느 것이든 허용되는 경우, 각 코덱마다 이 딕셔너리의 별도 인스턴스를 사용한다.
MediaKeySystemMediaCapability를
requestMediaKeySystemAccess()에
전달할 때는, 컨테이너가 이를 규범적으로 함의하지 않는 한
MIME 유형 안에 코덱 및 코덱 제약 조건을 지정하고
(예: [RFC6381]에
따름),
encryptionScheme을
null이라는 기본값에 의존하지 말고 특정 값으로 설정한다.
서로 다른 암호화 스킴은 일반적으로 서로 호환되지 않는다. null 기본값과 null을 "any"로 해석하는 것은 이를 알지 못하는 애플리케이션에 대한 하위 호환성과 오래된 사용자 에이전트를 위한 polyfill 경로를 제공한다.
MediaKeySystemAccess
객체는 키 시스템에 대한 접근을 제공한다.
WebIDL[Exposed=Window, SecureContext] interface MediaKeySystemAccess {
readonly attribute DOMString keySystem;
MediaKeySystemConfiguration getConfiguration ();
Promise<MediaKeys> createMediaKeys ();
};
keySystem 타입은 DOMString이며, 읽기 전용
getConfiguration()
requestMediaKeySystemAccess()
알고리즘이 선택한 지원되는 구성 옵션 조합을 반환한다.
반환되는 객체는 이 객체로 이행된 프로미스를 반환한
requestMediaKeySystemAccess()
호출에 전달된 첫 번째 충족 가능한 MediaKeySystemConfiguration
구성의 비엄격 부분집합(그리고 암시된 기본값)이다. 그 단일 구성에 지정되지 않은
기능에 대한 값은 포함하지 않으므로(암시된 기본값 제외), 키 시스템 구현의 모든 기능을
반영하지 않을 수 있다. 구성 안의 모든 값은 어떤 조합으로도 사용할 수 있다.
MediaKeysRequirement 타입의
멤버는 어떤 조합에 대해 기능이 요구되는지를 반영한다. 그 값은
"optional"이 되지 않는다.
이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 MUST 한다:
이 객체의 configuration 값을 반환한다.
이로 인해 이 메서드가 호출될 때마다 configuration에서 새 객체가 생성되고 초기화된다.
encryptionScheme이
애플리케이션에 의해 제공되지 않았더라도, 누적된 configuration은
여전히 값이 null인
encryptionScheme
필드를 포함해야 MUST 하므로,
polyfill은 특정 값을 지정하지 않고도 해당 필드에 대한 사용자 에이전트의
지원 여부를 감지할 수 있다.
createMediaKeys()
keySystem을 위한 새 MediaKeys 객체를
생성한다.
이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 MUST 한다:
promise를 새 프로미스로 둔다.
다음 단계를 병렬로 실행한다:
configuration을 이 객체의 configuration 값의 값으로 둔다.
configuration의
distinctiveIdentifier
멤버의 값이
"required"이면
use distinctive identifier를 true로 두고,
그렇지 않으면 false로 둔다.
configuration의 persistentState
멤버 값이 "required"이면
persistent state allowed를 true로 두고,
그렇지 않으면 false로 둔다.
필요한 경우 이 객체의 cdm implementation 값이 나타내는 키 시스템 구현을 로드하고 초기화한다.
instance를 이 객체의 cdm implementation 값이 나타내는 키 시스템 구현의 새 인스턴스로 둔다.
configuration을 사용하여 키 시스템 기능을 활성화, 비활성화 및/또는 선택하도록 instance를 초기화한다.
use distinctive identifier가 false이면,
instance가 구별
식별자 및 구별 영구 식별자를 사용하지 못하게 한다.
persistent state allowed가 false이면,
instance가 이 객체의 Document의 애플리케이션 또는
출처와
관련된 어떤 상태도 영속화하지 못하게 한다.
앞의 단계 중 하나라도 실패하면, 적절한 오류
이름을 이름으로 가지는 새
DOMException으로
promise를 거부한다.
media keys를 새 MediaKeys 객체로 두고,
다음과 같이 초기화한다:
use distinctive identifier 값을 use distinctive identifier로 둔다.
persistent state allowed 값을 persistent state allowed로 둔다.
supported session types 값을
configuration의 sessionTypes
멤버 값으로 둔다.
cdm implementation 값을 이 객체의 cdm implementation 값으로 둔다.
cdm instance 값을 instance로 둔다.
promise를 media keys로 이행한다.
promise를 반환한다.
MediaKeys 객체는 연결된
HTMLMediaElement가
재생 중 미디어
데이터의 복호화에
사용할 수 있는 키 집합을 나타낸다. 또한
CDM
인스턴스를 나타낸다.
MediaKeys 객체는 더 이상 접근할 수 없을 때
사용자 에이전트에 의해 파괴될 수 있다.
예를 들어, 스크립트 참조가 없고 연결된 미디어 요소도 없는 경우.
프로미스를 반환하는 메서드의 경우, 모든 오류는 반환된 Promise를 거부하여 비동기적으로 보고된다. 여기에는 [WEBIDL] 타입 매핑 오류도 포함된다.
알고리즘의 단계는 프로미스를 거부할 때 항상 중단된다.
WebIDLenum MediaKeySessionType {
"temporary",
"persistent-license"
};
MediaKeySessionType 열거형은 다음과 같이 정의된다:
| 열거형 설명 | |
|---|---|
temporary
|
라이선스, 키 및 세션의 기록 또는 세션과 관련된 데이터가 영속화되지 않는 세션. 애플리케이션은 그러한 저장소를 관리하는 것을 걱정할 필요가 없다. 이 세션 타입의 지원은 REQUIRED이다. |
persistent-license
|
라이선스(그리고 잠재적으로 세션과 관련된 다른 데이터)가 영속화되는 세션. 라이선스와 그 안에 포함된 키가 파괴될 때 라이선스 파기 기록은 영속화되어야 SHALL 한다. 라이선스 파기 기록은 라이선스와 그 안에 포함된 키가 더 이상 클라이언트에서 사용할 수 없다는 키 시스템별 증명이다. 이 세션 타입의 지원은 OPTIONAL이다.
이 타입의 세션은 이 객체를 생성한
애플리케이션은 그러한 세션에 대해 영속화된 데이터가 더 이상 필요하지 않을 때 제거되도록 보장할 책임이 있다. 세션 저장소 및 영속성을 참고한다. |
WebIDL[Exposed=Window, SecureContext] interface MediaKeys {
MediaKeySession createSession (optional MediaKeySessionType sessionType = "temporary");
Promise<MediaKeyStatus> getStatusForPolicy (optional MediaKeysPolicy policy = {});
Promise<boolean> setServerCertificate (BufferSource serverCertificate);
};
createSession()
새 MediaKeySession
객체를 반환한다.
sessionType 매개변수는 반환된 객체의 동작에 영향을 준다.
이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 MUST 한다:
이 객체의 supported session types 값이
sessionType을 포함하지 않으면, 던진다 [WEBIDL] .
NotSupportedError
영속 세션
타입인가?
알고리즘이 true를 반환하는 sessionType 값은
이 객체의 persistent
state allowed 값이 false이면 실패한다.
구현이 현재 상태에서 MediaKeySession 작업을
지원하지 않으면, 던진다 [WEBIDL] .
InvalidStateError
일부 구현은 이 MediaKeys
객체가
setMediaKeys()를
사용하여 미디어 요소와 연결될 때까지
MediaKeySession 알고리즘을
실행할 수 없다.
이 단계는 애플리케이션이 그러한 작업을 수행하려고 시도하기 전에 이 드문
동작을 감지할 수 있게 한다.
session을 새 MediaKeySession 객체로 두고,
다음과 같이 초기화한다:
sessionId
속성을 빈 문자열로 둔다.
expiration
속성을 NaN으로 둔다.
closed 속성을
새 프로미스로 둔다.
key status를 새 빈 MediaKeyStatusMap
객체로 두고, 다음과 같이 초기화한다:
size
속성을 0으로 둔다.
session type 값을 sessionType으로 둔다.
uninitialized 값을 true로 둔다.
callable 값을 false로 둔다.
closing or closed 값을 false로 둔다.
use distinctive identifier 값을 이 객체의 use distinctive identifier 값으로 둔다.
cdm implementation 값을 이 객체의 cdm implementation으로 둔다.
cdm instance 값을 이 객체의 cdm instance로 둔다.
session을 반환한다.
getStatusForPolicy()
주어진 MediaKeysPolicy에
대한 MediaKeyStatus를
반환한다.
WebIDLdictionary MediaKeysPolicy {
DOMString minHdcpVersion;
};
MediaKeysPolicy
딕셔너리는 선택적 속성만으로 구성된 객체이다. 각 속성은 정책 요구사항을 나타낸다.
CDM이 모든 요구사항에 기반하여 복호화된 미디어 데이터의
제시를 허용할 경우, 정책이 충족되었다고 한다.
HDCP 정책은 minHdcpVersion으로
나타낸다. 시스템이 지정된 HDCP 버전 이상을 활성화할 수 있으면, 그 정책은
"usable"의
MediaKeyStatus를
결과로 낳는다. [EME-HDCP-VERSION-REGISTRY]는
minHdcpVersion 값에서
HDCP 명세로의 매핑을 제공한다.
HDCP 상태의 결정은 CDM이 재생 중 그러한 제한을 강제하는 방식과 같은 방식으로 수행되어야 한다. 이렇게 하면 애플리케이션 개발자가 재생을 시작하기 위해 어떤 콘텐츠를 가져올지 최적화할 수 있도록 합리적인 힌트를 얻을 수 있다.
이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 MUST 한다:
TypeError로 거부된
프로미스를 반환한다.
promise를 새 프로미스로 둔다.
다음 단계를 실행하도록 태스크를 큐에 넣는다:
policy의 각 딕셔너리 멤버에 대해, 다음 단계를 실행한다:
키가 유효한 MediaKeysPolicy
멤버가 아니거나 값의 타입이 올바르지 않으면,
로
promise를 거부하고
이 단계를 중단한다.
TypeError
policy의 각 딕셔너리 멤버에 대해, 다음 단계를 실행한다:
CDM이
딕셔너리
멤버에 대한
MediaKeyStatus를
결정할 수 없으면,
로
promise를 거부하고 이 단계를 중단한다.
NotSupportedError
policy의 각 딕셔너리 멤버에 대해, 다음 단계를 실행한다:
CDM이
딕셔너리
멤버에 대해 복호화된 미디어 데이터의 제시를 차단할 것이라면,
promise를
"output-restricted"로
이행하고 이 단계를 중단한다.
promise를 "usable"로
이행한다.
promise를 반환한다.
setServerCertificate()
라이선스 서버로 보내는 메시지를 암호화하는 데 사용할 서버 인증서를 제공한다.
그러한 인증서를 사용하는 키 시스템의 경우, 애플리케이션은 서버 인증서를
명시적으로 설정하기 위해 SHOULD
setServerCertificate()를
호출해야 한다.
그렇지 않으면 라이선스 교환이 실패할 수 있다.
일부 키 시스템은 "message" 이벤트 큐에 넣기 알고리즘을 통해 서버에서 인증서를 요청하는 것도 지원한다. 하지만 그러한 인증서를 사용하는 모든 키 시스템이 이를 지원하는 것은 아니다.
서버 인증서 내용은 키 시스템별이다. 이는 실행 가능한 코드를 포함해서는 안 된다 MUST NOT.
이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 MUST 한다:
이 객체의 cdm
implementation 값이 나타내는 키 시스템
구현이 서버 인증서를 지원하지 않으면,
false로 이행된 프로미스를 반환한다.
serverCertificate가 빈 배열이면, 새로 생성된
로 거부된
프로미스를 반환한다.
TypeError
certificate를 serverCertificate 매개변수 내용의 사본으로 둔다.
promise를 새 프로미스로 둔다.
다음 단계를 병렬로 실행한다:
sanitized certificate를 certificate의 검증 및/또는 정제된 버전으로 둔다.
사용자 에이전트는 인증서를 CDM에 전달하기 전에 철저히 검증해야 한다. 여기에는 값이 합리적인 한계 안에 있는지 확인하고, 관련 없는 데이터나 필드를 제거하고, 미리 파싱하고, 정제하고, 및/또는 완전히 정제된 버전을 생성하는 것이 포함될 수 있다. 사용자 에이전트는 필드의 길이와 값이 합리적인지 확인해야 한다. 알 수 없는 필드는 거부하거나 제거해야 한다.
이 객체의 cdm instance를 사용하여 sanitized certificate를 처리한다.
앞의 단계가 실패하면, 적절한 오류
이름을 이름으로 가지는 새
DOMException으로
promise를 거부한다.
promise를 true로 이행한다.
promise를 반환한다.
영속 세션 타입인가? 알고리즘은 지정된 세션 타입이 어떤 종류의 영속성을 지원하는지
결정하기 위해 실행된다. 이 알고리즘을 실행하라는 요청에는
MediaKeySessionType
값이 포함된다.
다음 단계가 실행된다:
session type을 지정된 MediaKeySessionType 값으로 둔다.
다음 목록에서 session type의 값에 해당하는 단계를 따른다:
temporary"
false를 반환한다.
persistent-license"
true를 반환한다.
이 절은 저장소 및 영속성과 관련된 일반 요구사항을 설명한다.
MediaKeys 객체의 persistent state
allowed 값이
false이면, 그 객체의 cdm instance는 이 객체 또는 이 객체가 생성한
어떤 세션에 대한 작업의 결과로 상태를 영속화하거나 이전에 영속화된 상태에 접근해서는
안 된다 SHALL NOT.
MediaKeys 객체의 persistent state
allowed 값이
true이면, 그 객체의 cdm instance는 이 객체 또는 이 객체가 생성한
어떤 세션에 대한 작업의 결과로 상태를 영속화하거나 이전에 영속화된 상태에 접근할 수 있다
MAY.
영속화된 데이터는 항상 이 객체의 Document의 출처만 접근할 수 있도록 저장되어야 MUST 한다. 또한 데이터는 현재 브라우징 프로필에서만 접근 가능해야 MUST 한다. 다른 브라우징 프로필, 사용자 에이전트 및 애플리케이션은 저장된 데이터에 접근할 수 있어서는 안 된다 MUST NOT. 사용자 기기에 저장되는 정보를 참고한다.
영속 저장소를 지원할 때의 추가 고려사항은 10. 보안 및 11. 개인정보 보호를 참고한다.
MediaKeySession 객체는 키 세션을 나타낸다.
MediaKeySession 객체는 객체의
closed 속성이 이행된 경우 그리고
오직 그 경우에만 닫힘 상태이다.
사용자 에이전트는 CDM 상태 변경 감시 알고리즘을,
닫힘
상태가 아닌 각
MediaKeySession 객체에 대해 지속적으로
실행해야 SHALL 한다.
CDM 상태 변경 감시 알고리즘은 주 이벤트 루프와
병렬로 실행되어야 MUST 하지만, 이 명세에서 병렬로 실행되도록 정의된 다른 절차와는
병렬로 실행되어서는 안 된다.
MediaKeySession 객체는
닫힘
상태가 아니고 이를 생성한
MediaKeys
객체가 계속 접근 가능한 경우, 파괴되어서는 안 되며 SHALL
NOT 이벤트를 계속 수신해야 SHALL 한다.
그렇지 않으면, 더 이상 접근할 수 없는 MediaKeySession 객체는 더 이상
이벤트를 수신해서는 안 되며 SHALL NOT
파괴될 수 있다 MAY.
위 규칙은 CDM 인스턴스와 연결된 모든
MediaKeys 객체 및 모든 MediaKeySession 객체가 파괴될 때까지
CDM
인스턴스가 파괴되어서는 안 됨을 의미한다.
MediaKeySession 객체가 페이지에서 접근할 수 없게 될
때 닫힘 상태가 아니면,
CDM은 그
객체와 연결된
키 세션을 닫아야
SHALL 한다.
키 세션을 닫으면 명시적으로 저장되지 않은 모든 라이선스와 키가 폐기된다.
close()를
호출하고 반환된 promise를 기다린다.
자동 세션 닫힘의 타이밍에 의존하지 않는다.
키 세션이 정확히 언제 닫히는지는 구현 세부사항이다.
프로미스를 반환하는 메서드의 경우, 모든 오류는 반환된 Promise를 거부하여 비동기적으로 보고된다. 여기에는 [WEBIDL] 타입 매핑 오류도 포함된다.
알고리즘의 다음 단계는 프로미스를 거부할 때 항상 중단된다.
WebIDLenum MediaKeySessionClosedReason {
"internal-error",
"closed-by-application",
"release-acknowledged",
"hardware-context-reset",
"resource-evicted"
};
MediaKeySessionClosedReason 열거형은 다음과 같이 정의된다:
| 열거형 설명 | |
|---|---|
internal-error
|
세션은 CDM 안의 복구할 수 없는 오류 때문에 닫혔다. 이 상황이
발생하면, 애플리케이션은 이 MediaKeys 인스턴스에서 새 세션을
생성해서는
안 된다 MUST NOT.
|
closed-by-application
|
세션은 애플리케이션이 세션의
close()
메서드를 명시적으로 호출했기 때문에 닫혔다.
|
release-acknowledged
|
세션은 CDM이 라이선스 파기 기록 확인을 받았기 때문에 닫혔다. |
hardware-context-reset
|
세션은 CDM의 원래 하드웨어 컨텍스트가
재설정되었기 때문에 닫혔다.
이 상황이 발생하면, 사용자 에이전트는 애플리케이션이 이
MediaKeys 인스턴스에서 새 세션을 생성할 수
있도록 허용해야 MUST 한다.
참고
이는 장치 최대 절전, 모니터 구성 변경 등 많은 이유로 발생할 수 있다. 하드웨어 컨텍스트 재설정의 정확한 이유는 구현에 따라 다르다. |
resource-evicted
|
세션은 시스템이 다른 세션 생성을 허용하기 위해 리소스를 회수해야 했기 때문에 닫혔다.
참고
이는 애플리케이션이 세션 리소스에 대한 장치별 제한에 도달하고 있음을 의미한다. 닫힌 세션이 어떤 이유로 여전히 필요하다면, 애플리케이션 개발자는 필요한 세션 수를 줄이거나 필요 없는 세션을 선제적으로 닫는 전략을 고려해야 한다. |
WebIDL[Exposed=Window, SecureContext] interface MediaKeySession : EventTarget {
readonly attribute DOMString sessionId;
readonly attribute unrestricted double expiration;
readonly attribute Promise<MediaKeySessionClosedReason> closed;
readonly attribute MediaKeyStatusMap keyStatuses;
attribute EventHandler onkeystatuseschange;
attribute EventHandler onmessage;
Promise<undefined> generateRequest (DOMString initDataType, BufferSource initData);
Promise<boolean> load (DOMString sessionId);
Promise<undefined> update (BufferSource response);
Promise<undefined> close ();
Promise<undefined> remove ();
};
sessionId 타입은 DOMString이며, 읽기 전용
이 객체와 연결된 키 또는 라이선스에 대한 세션 ID.
expiration 타입은 unrestricted double이며,
읽기 전용
세션의 모든 키에 대한 만료 시간, 또는 그러한
시간이 존재하지 않거나 라이선스가 명시적으로 절대 만료되지 않는 경우
NaN으로, 이는 CDM에 의해 결정된다.
이 값은 세션 수명 동안 변경될 수 있으며, 예를 들어 어떤 동작이
윈도우의 시작을 트리거하는 경우가 이에 해당한다.
closed 타입은 Promise<MediaKeySessionClosedReason>이며,
읽기 전용
세션 닫힘 알고리즘이 실행된 결과로 객체가 닫힘 상태가 될 때 신호를 보낸다. 이 프로미스는 이행될 수만 있으며 절대 거부되지 않는다.
keyStatuses 타입은 MediaKeyStatusMap이며,
읽기 전용
세션에 알려진 키 ID에서 연결된 키의 현재 상태로 가는 읽기 전용 맵에 대한 참조. 각 항목은 고유한 키 ID를 가져야 MUST 한다.
맵 항목과 그 값은 이벤트 루프가 도는 언제든 갱신될 수 있다.
맵은 결코 불일치하거나 부분적으로 갱신되어서는 안 되지만 MUST NOT,
접근 사이에 이벤트 루프가 돌면 접근 사이에 변경될 수 있다. 키 ID는
load() 또는 update() 호출의
결과로 추가될 수 있다. 키 ID는 기존 키에 대한 지식을 제거하는(또는 기존 키 집합을
새 집합으로 대체하는)
update() 호출의
결과로 제거될 수 있다. 키 ID는 만료와 같이 사용할 수 없게 되었다는 이유로
제거되어서는 안 된다 MUST NOT.
대신, 그러한 키에는
"expired"와 같은 적절한
상태가 주어져야 MUST 한다.
일부 오래된 플랫폼에는 키 ID를 노출하지 않는 키 시스템 구현이
포함될 수 있으며, 이로 인해 준수하는 사용자 에이전트 구현을 제공하는 것이 불가능해진다. 그러한
경우 상호 운용성을 극대화하기 위해, 비어 있지 않은 목록이 적절할 때마다
이 객체의 집계된 상태에 가장 적절한 MediaKeyStatus와
1바이트 키 ID 0을 포함하는 단일 쌍으로 맵이 채워진다
(예: 이 객체가 나타내는 키 세션이
키를 포함할 수 있는 경우).
onkeystatuseschange 타입은 EventHandler
이벤트에 대한 이벤트 핸들러.
keystatuseschange
onmessage 타입은 EventHandler
이벤트에 대한 이벤트 핸들러.
message
generateRequest()
initData에 기반하여 라이선스 요청을 생성한다. 알고리즘이 성공하고
프로미스가 이행되면, 타입이
"license-request" 또는
"individualization-request"인
가 항상 큐에 들어간다.
message
이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 MUST 한다:
이 객체의 closing or closed 값이 true이면,
로
거부된 프로미스를 반환한다.
InvalidStateError
이 객체의 uninitialized 값이 false이면,
로
거부된 프로미스를 반환한다.
InvalidStateError
이 객체의 uninitialized 값을 false로 둔다.
initDataType이 빈 문자열이면, 새로 생성된
로 거부된
프로미스를 반환한다.
TypeError
initData가 빈 배열이면, 새로 생성된
로 거부된
프로미스를 반환한다.
TypeError
이 객체의 cdm
implementation 값이 나타내는 키 시스템
구현이
initDataType을
초기화 데이터
타입으로 지원하지 않으면,
로
거부된 프로미스를 반환한다.
문자열 비교는 대소문자를 구분한다.
NotSupportedError
init data를 initData 매개변수 내용의 사본으로 둔다.
session type을 이 객체의 session type으로 둔다.
promise를 새 프로미스로 둔다.
다음 단계를 병렬로 실행한다:
init data가 initDataType에 대해 유효하지 않으면,
새로 생성된 로
promise를 거부한다.
TypeError
sanitized init data를 init data의 검증되고 정제된 버전으로 둔다.
사용자 에이전트는 초기화 데이터를 CDM에 전달하기 전에 철저히 검증해야 MUST 한다. 여기에는 필드의 길이와 값이 합리적인지 확인하고, 값이 합리적인 한계 안에 있는지 확인하며, 관련 없거나 지원되지 않거나 알 수 없는 데이터 또는 필드를 제거하는 것이 포함된다. 사용자 에이전트가 초기화 데이터를 미리 파싱하고, 정제하고, 및/또는 완전히 정제된 버전을 생성하는 것이 RECOMMENDED된다. initDataType이 지정한 초기화 데이터 형식이 여러 항목을 지원하는 경우, 사용자 에이전트는 CDM이 필요로 하지 않는 항목을 제거해야 SHOULD 한다. 사용자 에이전트는 초기화 데이터 안의 항목 순서를 다시 정렬해서는 안 된다 MUST NOT.
앞의 단계가 실패하면, 새로 생성된
로
promise를 거부한다.
TypeError
sanitized init data가 비어 있으면,
로
promise를 거부한다.
NotSupportedError
session id를 빈 문자열로 둔다.
message를 null로 둔다.
message type을 null로 둔다.
cdm을 이 객체의 cdm instance 값이 나타내는 CDM 인스턴스로 둔다.
cdm을 사용하여 다음 단계를 실행한다:
sanitized init data가
cdm에서 지원되지 않으면, 로
promise를 거부한다.
NotSupportedError
다음 목록에서 session type의 값에 해당하는 단계를 따른다:
temporary"
requested license type을 영속화할 수 없는 임시 라이선스로 둔다.
반환되는 라이선스는 영속화할 수 없어야 하며, 이와 관련된 정보를 영속화할 것을 요구해서도 안 된다.
persistent-license"
requested license type을 영속화 가능한 라이선스로 둔다.
session id를 고유한 세션 ID 문자열로 둔다.
session type에 대해
영속 세션
타입인가? 알고리즘을 실행한 결과가 true이면,
그 ID는 이 객체의 Document의
출처
안에서,
Document와 브라우징 세션 전체를 포함하여 시간에 걸쳐 고유해야
MUST 한다.
message를 initDataType에 따라 해석된 sanitized init data에 기반하여 생성된, requested license type에 대한 라이선스 요청으로 둔다.
cdm은 sanitized init data를 통해 제공되지 않은 미디어 데이터를 포함하여 어떤 스트림별 데이터도 사용해서는 안 된다 MUST NOT.
cdm은 이 시점에서 세션 ID를 포함한 세션 데이터를 저장해서는 안 된다 SHOULD NOT. 세션 저장소 및 영속성을 참고한다.
message type을
"license-request"로
둔다.
message를 requested license type에 대한 라이선스 요청을 sanitized init data에 기반하여 생성하기 전에 처리되어야 하는 요청으로 둔다.
이후 update()
호출에서 CDM은
initDataType에 따라 해석되는
sanitized init
data에 기반하여 requested license
type에 대한 라이선스 요청을 생성해야
MUST 한다.
message type이
message의 타입,
즉 "license-request"
또는
"individualization-request"를
반영하게 한다.
다음 단계를 실행하도록 태스크를 큐에 넣는다:
앞의 단계 중 하나라도 리소스 부족 때문에 실패했으면,
로
promise를 거부한다.
QuotaExceededError
앞의 단계 중 하나라도 다른 이유로 실패했으면, 적절한
오류 이름을 이름으로 가지는 새
DOMException으로
promise를 거부한다.
sessionId
속성을 session id로 설정한다.
이 객체의 callable 값을 true로 설정한다.
promise를 undefined로 이행한다.
session에 대해 "message" 이벤트 큐에 넣기 알고리즘을 실행하고, message type과 message를 제공한다.
promise를 반환한다.
load()
지정된 세션에 대해 저장된 데이터를 이 객체로 로드한다.
이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 MUST 한다:
이 객체의 closing or closed 값이 true이면,
로
거부된 프로미스를 반환한다.
InvalidStateError
이 객체의 uninitialized 값이 false이면,
로
거부된 프로미스를 반환한다.
InvalidStateError
이 객체의 uninitialized 값을 false로 둔다.
sessionId가 빈 문자열이면, 새로 생성된
로 거부된
프로미스를 반환한다.
TypeError
이 객체의 session type에 대해
영속 세션 타입인가?
알고리즘을 실행한 결과가 false이면, 새로 생성된
로 거부된
프로미스를 반환한다.
TypeError
promise를 새 프로미스로 둔다.
다음 단계를 병렬로 실행한다:
sanitized session ID를 sessionId의 검증 및/또는 정제된 버전으로 둔다.
사용자 에이전트는 sessionId 값을 CDM에 전달하기 전에 철저히 검증해야 한다. 최소한 여기에는 길이와 값이 합리적인지 확인하는 것(예: 수십 문자보다 길지 않고 영숫자인지)이 포함되어야 한다.
앞의 단계가 실패했거나 sanitized session ID가 비어 있으면,
새로 생성된 로
promise를 거부한다.
TypeError
이 객체의 Document 안에
닫힘 상태가 아니며,
sessionId
속성이 sanitized session ID인
MediaKeySession 객체가
있으면,
로
promise를 거부한다.
QuotaExceededError
다시 말해, 이 브라우징 컨텍스트 안에서 이 sanitized session ID에 대해 닫히지 않은 세션이 타입과 관계없이 이미 존재하면 세션을 만들지 않는다.
expiration time을 NaN으로 둔다.
message를 null로 둔다.
message type을 null로 둔다.
cdm을 이 객체의 cdm instance 값이 나타내는 CDM 인스턴스로 둔다.
cdm을 사용하여 다음 단계를 실행한다:
origin 안에 sanitized session ID에 대해
저장된 데이터가 없으면, promise를 false로
이행하고
이 알고리즘의 병렬 단계를 중단한다.
저장된 세션의 session type이 현재
MediaKeySession
session type과 같지 않으면, 새로 생성된
로
promise를 거부한다.
TypeError
session data를 origin 안의 sanitized session ID에 대해 저장된 데이터로 둔다. 이는 다른 출처의 데이터나 출처와 연결되지 않은 데이터를 포함해서는 안 된다 MUST NOT.
어떤 Document
안에든 닫힘 상태가 아니며
session
data를 나타내는
MediaKeySession
객체가 있으면,
로
promise를 거부한다.
QuotaExceededError
다시 말해, 어떤 브라우징 컨텍스트 안에서든 이 sanitized session ID에 대해 닫히지 않은 영속 세션이 이미 존재하면 세션을 만들지 않는다.
session data를 로드한다.
session data가 세션의 만료 시간을 나타내면, expiration time을 그 만료 시간으로 둔다.
메시지를 보내야 하는 경우, 다음 단계를 실행한다:
message를 session data에 기반하여 생성된 메시지로 둔다.
message type을 그 메시지에 대한 적절한
MediaKeyMessageType으로
둔다.
다음 단계를 실행하도록 태스크를 큐에 넣는다:
앞의 단계 중 하나라도 실패했으면, 적절한 오류 이름으로 promise를 거부한다.
sessionId
속성을 sanitized session
ID로 설정한다.
이 객체의 callable 값을 true로 설정한다.
로드된 세션이 어떤 키에 대한 정보를 포함하면(알려진
키가 있으면),
session에 대해
키
상태 갱신 알고리즘을 실행하고,
각 키의 키 ID와
적절한 MediaKeyStatus를
제공한다.
키의 상태를 확실히 결정하기 위해 추가 처리가 필요하다면
"status-pending"을
사용한다.
하나 이상의 키에 대한 추가 처리가 완료되면,
실제 상태로 키
상태 갱신 알고리즘을 다시 실행한다.
session에 대해 만료 갱신 알고리즘을 실행하고, expiration time을 제공한다.
promise를 true로 이행한다.
message가 null이 아니면, session에 대해 "message" 이벤트 큐에 넣기 알고리즘을 실행하고, message type과 message를 제공한다.
promise를 반환한다.
update()
라이선스를 포함한 메시지를 CDM에 제공한다.
response 매개변수는 CDM에 제공할 메시지를 포함한다. 내용은 키 시스템별이다. 이는 실행 가능한 코드를 포함해서는 안 된다 MUST NOT.
이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 MUST 한다:
이 객체의 closing or closed 값이 true이면,
로
거부된 프로미스를 반환한다.
InvalidStateError
이 객체의 callable 값이 false이면,
로
거부된 프로미스를 반환한다.
InvalidStateError
response가 빈 배열이면, 새로 생성된
로 거부된
프로미스를 반환한다.
TypeError
response copy를 response 매개변수 내용의 사본으로 둔다.
promise를 새 프로미스로 둔다.
다음 단계를 병렬로 실행한다:
sanitized response를 response copy의 검증 및/또는 정제된 버전으로 둔다.
사용자 에이전트는 응답을 CDM에 전달하기 전에 철저히 검증해야 한다. 여기에는 값이 합리적인 한계 안에 있는지 확인하고, 관련 없는 데이터나 필드를 제거하고, 미리 파싱하고, 정제하고, 및/또는 완전히 정제된 버전을 생성하는 것이 포함될 수 있다. 사용자 에이전트는 필드의 길이와 값이 합리적인지 확인해야 한다. 알 수 없는 필드는 거부하거나 제거해야 한다.
앞의 단계가 실패했거나 sanitized response가 비어 있으면,
새로 생성된 로
promise를 거부한다.
TypeError
message를 null로 둔다.
message type을 null로 둔다.
session closed를 false로 둔다.
cdm을 이 객체의 cdm instance 값이 나타내는 CDM 인스턴스로 둔다.
cdm을 사용하여 다음 단계를 실행한다:
sanitized response의 형식이 어떤 방식으로든 유효하지
않으면, 새로 생성된 로
promise를 거부한다.
TypeError
다음 목록에서 첫 번째로 일치하는 조건에 대한 규정에 따라 sanitized response를 처리한다:
여기에는 초기 라이선스, 갱신된 라이선스, 라이선스 갱신 메시지가 포함된다.
다음 목록에서 첫 번째로 일치하는 조건에 대한 규정에 따라 sanitized response를 처리한다:
temporary"이고
sanitized response가 그 안에 포함된 모든
라이선스, 키 또는 유사한 세션 데이터를 포함한 세션 데이터를
저장해야 한다고 지정하지 않는 경우
persistent-license"이고
sanitized
response가 영속화 가능한 라이선스를 포함하는 경우
새로 생성된 로
promise를 거부한다.
TypeError
세션 저장소 및 영속성도 참고한다.
각 세션에 대한 키를 포함한 상태 정보는, 중복되는 키 ID를 포함하더라도 하나의 세션을 닫는 것이 다른 세션의 관찰 가능한 상태에 영향을 주지 않는 방식으로 저장되어야 MUST 한다.
sanitized response가 키 및/또는 관련 데이터를 포함하는 경우, cdm은 키 ID로 인덱싱된 키와 관련 데이터를 (메모리에) 저장할 가능성이 높다.
세션 안에서의 대체 알고리즘은 키 시스템에 따라 다르다.
CDM
구현이 표준적이고 합리적으로 높은
MediaKeySession
객체당 최소 키 수와 표준 대체 알고리즘, 그리고 표준적이고
합리적으로 높은
MediaKeySession
객체 수를 지원하는 것이 RECOMMENDED된다.
이는 합리적인 수의 키 로테이션 알고리즘이 사용자 에이전트
전반에서 구현될 수 있게 하며, 같은 요소의 다양한 스트림
(예: 적응형 스트림, 다양한 오디오 및 비디오 트랙)이 서로
다른 키를 사용하는 사용 사례에서 재생 중단 가능성을 줄일 수
있다.
persistent-license"인
경우
다음 단계를 실행한다:
키 세션을
닫고, 이 객체와 연결된 저장된 모든 세션
데이터를 지운다. 여기에는
sessionId와
라이선스
파기 기록이 포함된다.
session closed를 true로 설정한다.
예를 들어, sanitized response는 다른
이벤트를 생성하는 데 사용될 정보를 포함할 수 있다. 이 경우,
내용을 sessionType에 대해 검증할 필요가 없다.
message
메시지를 보내야 하는 경우, 다음 단계를 실행한다:
message를 그 메시지로 둔다.
message type을 그 메시지에 대한 적절한
MediaKeyMessageType으로
둔다.
다음 단계를 실행하도록 태스크를 큐에 넣는다:
이 객체에 대해 이유
"release-acknowledged"와
함께 세션 닫힘
알고리즘을 실행한다.
다음 단계를 실행한다:
이 객체에 대해 CDM에
알려진
키 집합이
변경되었거나 어떤 키의 상태가 변경되었으면,
session에 대해 키
상태 갱신 알고리즘을 실행하고,
각 알려진 키의 키 ID와
적절한
MediaKeyStatus를
제공한다.
키의 상태를 확실히 결정하기 위해 추가 처리가
필요하다면
"status-pending"을
사용한다.
하나 이상의 키에 대한 추가 처리가 완료되면,
실제 상태로 키
상태 갱신 알고리즘을 다시 실행한다.
세션의 만료 시간이 변경되었으면, session에 대해 만료 갱신 알고리즘을 실행하고, 새 만료 시간을 제공한다.
앞의 단계 중 하나라도 실패했으면, 적절한
오류 이름을 이름으로 가지는
새 DOMException으로
promise를 거부한다.
message가 null이 아니면, session에 대해 "message" 이벤트 큐에 넣기 알고리즘을 실행하고, message type과 message를 제공한다.
promise를 undefined로 이행한다.
promise를 반환한다.
close()
애플리케이션이 더 이상 세션을 필요로 하지 않으며 CDM이 세션과 연결된 모든 리소스를 해제하고 이를 닫아야 함을 나타낸다. 영속화된 데이터는 해제되거나 지워져서는 안 된다.
반환된 프로미스는 요청이 처리되면 이행되며,
closed 속성 프로미스는
세션이 닫힐 때
"closed-by-application"로
이행된다.
이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 MUST 한다:
이 객체의 closing or closed 값이 true이면,
undefined로 이행된 프로미스를 반환한다.
이 객체의 callable 값이 false이면,
로
거부된 프로미스를 반환한다.
InvalidStateError
promise를 새 프로미스로 둔다.
이 객체의 closing or closed 값을 true로 설정한다.
다음 단계를 병렬로 실행한다:
cdm을 이 객체의 cdm instance 값이 나타내는 CDM 인스턴스로 둔다.
cdm을 사용하여 이 객체와 연결된 키 세션을 닫는다.
키 세션을 닫으면 명시적으로 저장되지 않은 모든 라이선스와 키가 파괴된다.
다음 단계를 실행하도록 태스크를 큐에 넣는다:
promise를 undefined로 이행한다.
이 객체에 대해 이유
"closed-by-application"와
함께 세션
닫힘 알고리즘을 실행한다.
promise를 반환한다.
remove()
세션과 연결된 모든 라이선스와 키를 제거한다. 영속 세션 타입의 경우, 릴리스 메시지 확인이
update()에 의해
처리되면 각 세션 타입에 대해 정의된 대로 다른 세션 데이터가 지워진다.
이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 MUST 한다:
이 객체의 closing or closed 값이 true이면,
로
거부된 프로미스를 반환한다.
InvalidStateError
이 객체의 callable 값이 false이면,
로
거부된 프로미스를 반환한다.
InvalidStateError
promise를 새 프로미스로 둔다.
다음 단계를 병렬로 실행한다:
cdm을 이 객체의 cdm instance 값이 나타내는 CDM 인스턴스로 둔다.
message를 null로 둔다.
message type을 null로 둔다.
cdm을 사용하여 다음 단계를 실행한다:
세션과 연결된 라이선스 및/또는 키가 있으면:
세션과 연결된 라이선스 및/또는 키를 파괴한다.
이는 라이선스 및/또는 키가 메모리, 영속 저장소 또는 둘 다에 있는지와 관계없이 이를 파괴함을 의미한다.
다음 목록에서 이 객체의 session type 값에 해당하는 단계를 따른다:
temporary"
다음 단계를 계속한다.
persistent-license"
record of license destruction를 이 객체가 나타내는 라이선스에 대한 라이선스 파기 기록으로 둔다.
record of license destruction를 저장한다.
message를 record of license destruction을 포함하거나 반영하는 메시지로 둔다.
다음 단계를 실행하도록 태스크를 큐에 넣는다:
session에 대해
키 상태
갱신
알고리즘을 실행하고,
세션 안의 모든 키 ID와
각 키에 대한
"released"
MediaKeyStatus
값을 제공한다.
session에 대해
만료 갱신
알고리즘을
실행하고,
NaN을 제공한다.
앞의 단계 중 하나라도 실패했으면, 적절한
오류 이름을 이름으로 가지는 새
DOMException으로
promise를 거부한다.
message type을 "license-release"로
둔다.
promise를 undefined로 이행한다.
message가 null이 아니면,
session에 대해
"message"
이벤트 큐에 넣기 알고리즘을 실행하고,
message type과 message를 제공한다.
promise를 반환한다.
MediaKeyStatusMap 객체는
키 ID에서 연결된 키의 현재 상태로
가는 읽기 전용 맵이다.
키의 상태는 그 키가 현재 사용 중인지 여부 및 미디어 데이터와 독립적이다.
예를 들어, 어떤 키에 현재 충족될 수 없는 출력 요구사항이 있다면,
그 키가 미디어 데이터를 복호화하는 데 필요했는지 또는 현재 필요한지 여부와 관계없이,
키의 상태는 적절하게 "output-downscaled" 또는
"output-restricted"여야 한다.
WebIDL[Exposed=Window, SecureContext] interface MediaKeyStatusMap {
iterable<BufferSource,MediaKeyStatus>;
readonly attribute unsigned long size;
boolean has (BufferSource keyId);
(MediaKeyStatus or undefined) get (BufferSource keyId);
};
size 타입은 unsigned long이며,
읽기 전용
알려진 키의 수.
has()
keyId가 식별하는 키의 상태가 알려져 있으면 true를 반환한다.
get()
keyId가 식별하는 키의
MediaKeyStatus를
반환하거나, keyId가 식별하는 키의 상태가 알려져 있지 않으면
undefined를 반환한다.
이 인터페이스는 iterable
[WebIDL]에 의해 제공되는
entries, keys, values,
forEach 및 @@iterator 메서드를 가진다.
반복할 값 쌍은 모든 알려진 키에 대해
키 ID와 연결된
MediaKeyStatus 값으로 형성된 쌍의 집합을
키 ID로 정렬한 스냅샷이다. 키 ID는 다음과 같이
비교된다: 길이가 m인 키 ID A와 길이가 n인
키 ID B에 대해, m <= n이 되도록 배정하면,
A의 m 옥텟이 B의 처음 m 옥텟보다
사전식 순서로 작거나, 그 옥텟들이 같고 m < n인 경우 그리고
오직 그 경우에만 A < B로 둔다.
WebIDLenum MediaKeyStatus {
"usable",
"expired",
"released",
"output-restricted",
"output-downscaled",
"usable-in-future",
"status-pending",
"internal-error"
};
MediaKeyStatus 열거형은 다음과 같이 정의된다:
| 열거형 설명 | |
|---|---|
usable
|
CDM은 키가 현재 복호화에 사용할 수 있음을 확신한다. 현재 복호화에 사용할 수 없을 수도 있는 키는 이 상태를 가져서는 안 된다 MUST NOT. |
expired
|
키의 만료 시간이 지났기 때문에 키는 더 이상
복호화에 사용할 수 없다.expiration 속성이 나타내는
시간은 현재 시간보다 이전이어야 MUST 한다. 세션 안의 다른 모든 키도 이 상태를 가져야
MUST 한다.
|
released
|
키 자체는 더 이상 CDM에서 사용할 수 없지만, 라이선스 파기 기록과 같은 키에 대한 정보는 사용할 수 있다. |
output-restricted
|
키와 연결된 출력 제한이 있으며, 이는 현재 충족될 수 없다. 이 키로 복호화된 미디어 데이터는 출력 제한에 따라 필요한 경우 제시가 차단될 수 있다. 애플리케이션은 키와 연결된 출력 제한을 트리거할 스트림의 사용을 피해야 한다. |
output-downscaled
|
키와 연결된 출력 제한이 있으며, 이는 현재 충족될 수 없다.
이 키로 복호화된 미디어 데이터는 출력 제한에 따라 필요한 경우 더 낮은 품질(예:
해상도)로 제시될 수 있다. 애플리케이션은 키와 연결된 출력 제한을 트리거할
스트림의 사용을 피해야 한다. 다운스케일링 지원은 OPTIONAL이다. 애플리케이션은 출력 요구사항을 충족할 수 없을 때 중단 없는 재생을 보장하기 위해 다운스케일링에 의존해서는 안 된다 SHOULD NOT. |
usable-in-future
|
시작 시간이 미래이기 때문에 키는 아직 복호화에 사용할 수 없다. 키는 그 시작 시간에 도달하면 사용할 수 있게 된다. |
status-pending
|
키의 상태는 아직 알려져 있지 않으며 결정 중이다. 상태가 결정되면 실제 상태로 갱신된다. |
internal-error
|
다른 값과 무관한 CDM 안의 오류 때문에 키는 현재 복호화에 사용할 수 없다. 이 값은 애플리케이션이 조치할 수 있는 값이 아니다. |
MediaKeyMessageEvent 객체는
이벤트에 사용된다.
message
WebIDLenum MediaKeyMessageType {
"license-request",
"license-renewal",
"license-release",
"individualization-request"
};
MediaKeyMessageType은 다음과 같이 정의된다:
| 열거형 설명 | |
|---|---|
license-request
|
메시지는 새 라이선스에 대한 요청을 포함한다. |
license-renewal
|
메시지는 기존 라이선스를 갱신하기 위한 요청을 포함한다. |
license-release
|
메시지는 라이선스 파기 기록을 포함한다. |
individualization-request
|
메시지는 앱 지원 개별화(또는
재개별화)에 대한
요청을 포함한다. 다른 모든 메시지와 마찬가지로, 메시지 안의 모든 식별자는 출처 및 프로필별로 구별되어야 MUST 하며, 구별 영구 식별자여서는 안 된다 MUST NOT. |
WebIDL[Exposed=Window, SecureContext]
interface MediaKeyMessageEvent : Event {
constructor(DOMString type, MediaKeyMessageEventInit eventInitDict);
readonly attribute MediaKeyMessageType messageType;
readonly attribute ArrayBuffer message;
};
messageType 타입은 MediaKeyMessageType이며, 읽기 전용
구현은 애플리케이션이 메시지 타입을 처리하도록 요구해서는 안 된다 MUST NOT. 구현은 메시지를 구별하지 않는 애플리케이션을 지원해야 MUST 하며, 애플리케이션이 메시지 타입을 처리하도록 요구해서는 안 된다 MUST NOT. 구체적으로, 키 시스템은 모든 타입의 메시지를 단일 URL로 전달하는 것을 지원해야 MUST 한다.
이 속성은 애플리케이션이 메시지를 파싱하지 않고 메시지를 구별할 수 있게 한다. 이는 선택적 애플리케이션 및/또는 서버 최적화를 가능하게 하기 위한 것이지만, 애플리케이션이 이를 사용해야 하는 것은 아니다.
message 타입은 ArrayBuffer이며,
읽기 전용
WebIDLdictionary MediaKeyMessageEventInit : EventInit {
required MediaKeyMessageType messageType;
required ArrayBuffer message;
};
MediaKeyMessageEventInit
멤버
messageType
타입은 MediaKeyMessageType
message
타입은 ArrayBuffer
이 절은 비규범적이다.
| 이벤트 이름 | 인터페이스 | 디스패치되는 시점... |
|---|---|---|
keystatuseschange
|
Event
|
세션의 키 또는 그 상태에 변경이 있었다. |
message
|
MediaKeyMessageEvent
|
CDM이 세션에 대한 메시지를 생성했다. |
"message" 이벤트 큐에 넣기 알고리즘은 메시지 이벤트를
MediaKeySession
객체에 큐에 넣는다. 이 알고리즘을 실행하라는 요청에는 대상
MediaKeySession 객체,
message type, 그리고 message가 포함된다.
message는 암호화된 형태라 하더라도
구별 영구 식별자를 포함해서는
안 된다 MUST NOT.
message는 MediaKeySession 객체의
use distinctive
identifier 값이 false인 경우, 암호화된 형태라 하더라도
구별 식별자를 포함해서는 안 된다
MUST NOT.
다음 단계가 실행된다:
session을 지정된 MediaKeySession 객체로 둔다.
버블링하지 않고 취소할 수 없는 라는
이름의 이벤트를
생성하고, messageMediaKeyMessageEvent
인터페이스를 사용하여 그 type 속성을 message로 설정하고
그 isTrusted 속성을 true로 초기화한 뒤,
session에 발송하도록
태스크를
큐에 넣는다.
이벤트 인터페이스 MediaKeyMessageEvent는 다음을
가진다:
messageType =
지정된 message
typemessage = 지정된
message
키 상태 갱신 알고리즘은 MediaKeySession에 대한
알려진 키 집합 또는
하나 이상의 키 상태를 갱신한다. 이 알고리즘을 실행하라는 요청에는 대상
MediaKeySession 객체와
키 ID 및 연결된
MediaKeyStatus 쌍의
시퀀스가 포함된다.
이 알고리즘은 항상 태스크 안에서 실행된다.
다음 단계가 실행된다:
session을 연결된 MediaKeySession 객체로 둔다.
input statuses를 키 ID 및 연결된
MediaKeyStatus
쌍의 시퀀스로 둔다.
statuses를 session의 keyStatuses
속성으로 둔다.
statuses의 내용을 대체하기 위해 다음 단계를 실행한다:
statuses를 비운다.
input statuses의 각 쌍에 대해.
pair를 그 쌍으로 둔다.
pair의 키 ID에 대한 항목을 statuses에 삽입하고,
그 값을 pair의
MediaKeyStatus
값으로 한다.
이 단계의 효과는 session의
keyStatuses
속성에 대한 기존 참조를 무효화하지 않고 그 내용을 대체하는 것이다. 이 대체는
스크립트 관점에서 원자적이다. 즉, 스크립트는 부분적으로 채워진 시퀀스를 결코
보아서는 안 된다 MUST NOT.
session에서 라는
이름의 이벤트를 발화하도록
태스크를
큐에 넣는다.
keystatuseschange
session을 생성한
MediaKeys 객체가
mediaKeys 속성인
각 미디어 요소에 대해
필요하면 재생
재개 시도
알고리즘을 실행하도록 태스크를
큐에 넣는다.
만료 갱신 알고리즘은
MediaKeySession의
만료 시간을
갱신한다. 이 알고리즘을 실행하라는 요청에는 대상
MediaKeySession 객체와 새 만료 시간이
포함되며, 이는 NaN일 수 있다.
이 알고리즘은 항상 태스크 안에서 실행된다.
다음 단계가 실행된다:
session을 연결된 MediaKeySession 객체로 둔다.
expiration time을 NaN으로 둔다.
새 만료 시간이 NaN이 아니면, expiration time을 그 만료
시간으로 둔다.
session의 expiration 속성을
시간으로 표현된
expiration time으로 설정한다.
세션 닫힘 알고리즘은 CDM에 의해
키 세션이 닫힌 후
MediaKeySession 상태를 갱신한다.
이 알고리즘을 실행하라는 요청에는 대상
MediaKeySession 객체와
MediaKeySessionClosedReason이
포함된다.
이 알고리즘은 항상 태스크 안에서 실행된다.
세션이 닫히면, 그 세션과 연결된 라이선스와 키는 더 이상
미디어
데이터를
복호화하는 데 사용할 수 없다. 이 알고리즘이 실행된 후에는 모든
MediaKeySession 메서드가 실패하고,
이 객체에 대해 더 이상의 이벤트가 큐에 들어가지 않는다.
CDM은 세션이 더 이상 필요하지 않거나 시스템 리소스가 손실된 경우와 같이 언제든 세션을 닫을 수 있다. 이 경우 CDM 상태 변경 감시 알고리즘이 변경을 감지하고 이 알고리즘을 실행한다.
다른 세션의 키는 중복되는 키 ID를 가지더라도 영향을 받아서는 안 된다 MUST.
이 알고리즘이 실행된 후에는 이 알고리즘이 큐에 넣은 이벤트에 대한 이벤트 핸들러가 실행되지만, 더 이상의 이벤트는 큐에 넣을 수 없다. 그 결과 세션을 닫는 것의 결과로 CDM이 메시지를 보낼 수 없다.
다음 단계가 실행된다:
session을 연결된 MediaKeySession 객체로 둔다.
promise를 session의 closed
속성으로 둔다.
promise가 이행되었으면, 이 단계를 중단한다.
session의 closing or closed 값을 true로 설정한다.
session에 대해 키 상태 갱신 알고리즘을 실행하고 빈 시퀀스를 제공한다.
session에 대해 만료 갱신 알고리즘을
실행하고
NaN을 제공한다.
promise를 제공된 이유로 이행한다.
CDM 상태 변경 감시 알고리즘은 CDM 상태의 다양한 측면이 변경될 때 필요한 단계를 실행한다.
이 알고리즘은 다른 알고리즘이 다루지 않는
CDM 상태 변경에만 적용된다.
예를 들어 update()는
메시지, 키 상태 변경 및/또는 만료 변경을 일으킬 수 있지만, 그것들은 모두 그
알고리즘 안에서 처리된다.
이 알고리즘은 항상 주 이벤트 루프와 병렬로 실행된다.
다음 단계가 실행된다:
session을 MediaKeySession 객체로 둔다.
cdm을 session의 cdm instance 값이 나타내는 CDM 인스턴스로 둔다.
cdm에 아직 전송되지 않은 나가는 메시지가 있으면, 다음 단계를 실행하도록 태스크를 큐에 넣는다:
message type과 message를 각각 메시지 타입과 메시지로 둔다.
session, message type 및 message를 전달하여 "message" 이벤트 큐에 넣기 알고리즘을 실행한다.
cdm이 session에 알려진 키 집합 또는 하나 이상의 키 상태를 변경했으면, 다음 단계를 실행하도록 태스크를 큐에 넣는다:
statuses를 session에
알려진 각
키에 대해 하나의 쌍을 포함하는 키 ID 및
MediaKeyStatus 값 쌍의
목록으로 둔다.
session과 statuses를 전달하여 키 상태 갱신 알고리즘을 실행한다.
cdm이 session의 만료 시간을 변경했으면, 다음 단계를 실행하도록 태스크를 큐에 넣는다:
expiration time을 session의 새 만료 시간으로 둔다.
session과 expiration time을 전달하여 만료 갱신 알고리즘을 실행한다.
cdm이 session을 닫았으면, 적절한
MediaKeySessionClosedReason
값과 함께 session에 대해
세션 닫힘 알고리즘을 실행하도록
태스크를
큐에 넣는다.
cdm이 하드웨어 컨텍스트 재설정 때문에 사용할 수 없게 되었으면, 이유
"hardware-context-reset"와
함께 CDM 사용 불가 알고리즘을
실행하도록 태스크를
큐에 넣는다.
cdm이 다른 이유로 사용할 수 없게 되었으면, 이유
"internal-error"와
함께 CDM 사용 불가 알고리즘을 실행하도록
태스크를
큐에 넣는다.
메서드는 반환된 프로미스를 simple exception
[WEBIDL] 또는 DOMException으로 거부하여
오류를 보고한다. 다음의 simple
exceptions 및 [WEBIDL]의
DOMException 이름이
알고리즘에서 사용된다. 알고리즘에서 지정된 원인은 각 이름 옆에 나열되어 있지만,
이 이름들은 다른 이유로도 사용될 수 있다 MAY.
| 이름 | 가능한 원인(전체 목록 아님) |
|---|---|
TypeError
|
매개변수가 비어 있음. 유효하지 않은 초기화 데이터. 유효하지 않은 응답 형식. " temporary"
세션에 영속 라이선스가 제공됨.
|
NotSupportedError
|
기존 MediaKeys 객체를
제거할 수 없음.키 시스템이 지원되지 않음. 초기화 데이터 타입이 키 시스템에서 지원되지 않음. 세션 타입이 키 시스템에서 지원되지 않음. 초기화 데이터가 키 시스템에서 지원되지 않음. 작업이 키 시스템에서 지원되지 않음. |
InvalidStateError
|
기존 MediaKeys 객체를
지금 제거할 수 없음.세션이 이미 사용됨. 세션이 아직 초기화되지 않음. 세션이 닫힘. |
QuotaExceededError
|
MediaKeys 객체를 추가
HTMLMediaElement와 함께 사용할 수
없음.이 sessionId에 대해 닫히지 않은 세션이 이미 존재함. 새 세션 또는 라이선스 요청을 생성할 리소스가 충분하지 않음. |
이 절은 알고리즘을 보완하는 세션 저장소와 지속성에 대한 개요를 제공한다.
다음 요구사항은 저장소와 지속성의 요구사항에 추가로 적용된다.
이 객체의 session type에 대해 지속 세션 유형인가?
알고리즘을 실행한 결과가 false이면, 사용자 에이전트와 CDM은 어느 시점에도
세션의 기록이나 세션과 관련된 데이터를 지속시켜서는 MUST
NOT 된다. 여기에는
라이선스, 키, 라이선스
폐기 기록, 그리고 세션 ID가 포함된다.
이 절의 나머지는 지속 세션 유형인가? 알고리즘이
true를 반환하는 세션 유형에 적용된다.
CDM은
update()가 처음 호출되기 전까지
세션 ID를 포함한 세션 데이터를 저장하지 않는 것이 SHOULD NOT 된다.
구체적으로, CDM은 generateRequest()
알고리즘 동안 세션 데이터를 저장하지 않는 것이 SHOULD NOT 된다. 이는
애플리케이션이 세션을 인식하고 결국 이를 제거해야 함을 알도록 보장한다.
세션이 삭제될 때 세션과 관련된 모든 데이터는 삭제되어야 MUST 하며,
예를 들어 update()에서
라이선스 폐기 기록
확인 응답을 처리할 때가 이에 해당한다. 지속
데이터를 보라.
CDM은
주어진 세션의 데이터가 어떤 Document에서도 닫히지 않은 하나의
MediaKeySession 객체에만 존재하도록 보장해야
MUST 한다.
다시 말해, sessionId 매개변수로 지정된 세션을 나타내는
MediaKeySession이 이미 있는 경우,
load()는 실패해야
MUST 한다. 이는
generateRequest()를
통해
이를 생성한 객체가 여전히 활성 상태이거나, load()를 통해
다른
객체에 로드되었기 때문일 수 있다. 세션은 이를 나타낸 적이 있는 모든 객체가
닫힌 경우에만 다시 로드될 MAY 수 있다.
지속 세션 유형인가? 알고리즘이
true를 반환하는 유형을 사용해 세션을 생성하는 애플리케이션은, 나중에 먼저
remove()를 사용하여
제거 프로세스를 시작한 다음,
메시지 교환을 포함할 수 있는 제거 프로세스가 성공적으로 완료되도록 보장함으로써
저장된 데이터를 제거하는 것이 SHOULD 된다. CDM도
적절한 경우 세션을 제거할 MAY 수 있지만, 애플리케이션은 이에 의존하지 않는 것이 SHOULD
NOT 된다.
지속 저장소를 지원할 때의 추가 고려사항은 10. 보안 및 11. 개인정보 보호를 보라.
이 절은 Encrypted Media Extensions가 지원될 때
HTMLMediaElement [HTML]에 대한
추가 및 수정을 명시한다.
다음 내부 값들이 HTMLMediaElement에 추가된다:
attaching media keys, 이는 boolean 값을 가져야 SHALL 한다.
encrypted block queue, 이는 복호화를 기다리는 암호화된 블록의 큐여야 SHALL 한다.
decryption blocked waiting for key, 이는 boolean 값을 가져야 SHALL 한다.
playback blocked waiting for key, 이는 boolean 값을 가져야 SHALL 한다.
HTMLMediaElement의 동작에는 다음 수정이
이루어진다:
HTMLMediaElement가
생성될 때, 그 attaching media keys 값은 false로 초기화되어야
SHALL 하고, 그 encrypted block queue 값은 비어 있어야
SHALL 하며, 그 decryption blocked waiting for key 값은
false로 초기화되어야 SHALL 하고, 그
playback blocked waiting for key 값은 false로 초기화되어야
SHALL 한다.
정상 재생의 일부로 재생
방향으로 진행하는 것이 아닌 방식으로
현재 재생 위치가
변경되면, encrypted block queue 값은 비어 있어야
SHALL 하고, decryption blocked waiting for key 값은
false로 초기화되어야 SHALL 하며,
playback blocked waiting for key 값은 false로 설정되어야
SHALL 한다.
다시 말해, 예를 들어 미디어 리소스 로드 또는 탐색 시 이 값들은 재설정되는 것이 좋다.
[HTML]에 명시된 기준에 더해,
HTMLMediaElement는 그
playback blocked waiting for key 값이 true이면
차단된 미디어 요소로
간주되어야 SHALL 한다.
사용자 에이전트가 재생을 시작할 준비가 되었고 리소스 가져오기 알고리즘 동안 미디어 데이터가 암호화된 블록을 포함할 수 있음을 나타내는 표시를 만났으면, 사용자 에이전트는 미디어 데이터가 암호화된 블록을 포함할 수 있음 알고리즘을 실행해야 SHALL 한다.
일부 컨테이너 형식에서 그러한 표시는 초기화 데이터와 별개이다.
이 알고리즘은 초기화 데이터 발견 알고리즘 실행을 포함하여 관련 컨테이너 데이터를 파싱한 후, 디코딩이 시작되기 전에 실행된다.
사용자 에이전트가 초기화 데이터를 미디어 데이터 안에서 리소스 가져오기 알고리즘 동안 만나면, 사용자 에이전트는 초기화 데이터 발견 알고리즘을 실행해야 SHALL 한다.
일부 컨테이너 형식은 초기화 데이터를 포함하지 않는 암호화된 미디어 데이터를 지원할 수 있으므로, 이 알고리즘을 트리거하지 않는 미디어 데이터를 지원할 수 있다.
리소스 가져오기 알고리즘 동안 만난 암호화된 미디어 데이터의 각 블록에 대해, 사용자 에이전트는 암호화된 블록을 만난 순서대로 암호화된 블록 발견 알고리즘을 실행해야 SHALL 한다.
위 단계는 사용자 에이전트 구현이 암호화된 블록을 만난 후 재생에 필요해지기 전 언제든 복호화를 수행할 수 있는 유연성을 제공한다.
decryption blocked waiting for
key 값이 true인 동안 다음 중 하나가 발생하면, 사용자 에이전트는
키 대기
알고리즘을 실행해야 SHALL 한다.
아래에 명시된 대로 추가 속성과 메서드가 추가된다.
프로미스를 반환하는 메서드의 경우, 모든 오류는 반환된 Promise를 거부하여 비동기적으로 보고된다. 여기에는 [WEBIDL] 타입 매핑 오류도 포함된다.
알고리즘의 단계는 프로미스를 거부할 때 항상 중단된다.
WebIDL[Exposed=Window] partial interface HTMLMediaElement {
[SecureContext] readonly attribute MediaKeys? mediaKeys;
attribute EventHandler onencrypted;
attribute EventHandler onwaitingforkey;
[SecureContext] Promise<undefined> setMediaKeys (MediaKeys? mediaKeys);
};
mediaKeys 타입은 MediaKeys이며, 읽기 전용, nullable
onencrypted 타입은 EventHandler
이벤트에 대한 이벤트 핸들러. 이는 모든
encryptedHTMLMediaElement가
콘텐츠 속성과 IDL 속성 모두로 지원해야 MUST 한다.
onwaitingforkey 타입은 EventHandler
이벤트에 대한
이벤트 핸들러. 이는 모든
waitingforkeyHTMLMediaElement가
콘텐츠 속성과 IDL 속성 모두로 지원해야 MUST 한다.
setMediaKeys()
재생 중 미디어 데이터를 복호화할 때 사용할
MediaKeys를 제공한다.
재생 중 연결된 MediaKeys 객체를 지우거나
교체하는
것의 지원은 구현 품질 문제이다. 많은 경우 이는 좋지 않은 사용자 경험이나
거부된 프로미스를 초래한다.
이 메서드가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 MUST 한다:
이 객체의 attaching media keys 값이 true이면,
로
거부된 프로미스를 반환한다.
InvalidStateError
mediaKeys와 mediaKeys 속성이
같은 객체이면, undefined로 이행된 프로미스를 반환한다.
이 객체의 attaching media keys 값을 true로 둔다.
promise를 새 프로미스로 둔다.
다음 단계를 병렬로 실행한다:
다음 조건이 모두 성립하면:
mediaKeys가 null이 아니고,
mediaKeys가 나타내는 CDM 인스턴스가 이미 다른 미디어 요소에서 사용 중이며
사용자 에이전트가 이를 이 요소와 함께 사용할 수 없으면
이 객체의 attaching media keys 값을 false로 두고,
로
promise를 거부한다.
QuotaExceededError
mediaKeys
속성이 null이 아니면, 다음 단계를 실행한다:
사용자 에이전트 또는 CDM이 연결 제거를
지원하지 않으면, 이 객체의 attaching media keys 값을
false로 두고 로
promise를 거부한다.
NotSupportedError
연결을 현재 제거할 수 없으면, 이 객체의
attaching media keys 값을 false로 두고
로
promise를 거부한다.
InvalidStateError
예를 들어, 일부 구현은 재생 중 제거를 허용하지 않을 수 있다.
mediaKeys
속성이 나타내는 CDM 인스턴스를
미디어
데이터 복호화에 사용하는 것을 중지하고, 미디어 요소와의
연결을 제거한다.
앞의 단계가 실패했으면, 이 객체의 attaching media keys 값을 false로 두고 적절한 오류 이름으로 promise를 거부한다.
mediaKeys가 null이 아니면, 다음 단계를 실행한다:
앞의 단계가 실패했으면, 다음 단계를 실행한다:
mediaKeys
속성을 null로 설정한다.
이 객체의 attaching media keys 값을 false로 둔다.
이름이 적절한 오류 이름인 새
DOMException으로
promise를 거부한다.
미디어 요소에 대해 필요하면 재생 재개 시도 알고리즘을 실행하도록 태스크를 큐에 넣는다.
mediaKeys
속성을 mediaKeys로 설정한다.
이 객체의 attaching media keys 값을 false로 둔다.
promise를 undefined로 이행한다.
promise를 반환한다.
MediaEncryptedEvent
인터페이스
MediaEncryptedEvent 객체는 이벤트에 사용된다.
encrypted
WebIDL[Exposed=Window]
interface MediaEncryptedEvent : Event {
constructor(DOMString type, optional MediaEncryptedEventInit eventInitDict = {});
readonly attribute DOMString initDataType;
readonly attribute ArrayBuffer? initData;
};
initDataType 타입은 DOMString이며, 읽기 전용
initData 속성에 포함된
초기화 데이터의
초기화 데이터 타입을
나타낸다.
initData 타입은 ArrayBuffer이며,
읽기 전용, nullable
WebIDLdictionary MediaEncryptedEventInit : EventInit {
DOMString initDataType = "";
ArrayBuffer? initData = null;
};
MediaEncryptedEventInit
멤버
initDataType
타입은 DOMString이며,
기본값은
""
initData
타입은 ArrayBuffer이며,
nullable, 기본값은
null
이 절은 비규범적이다.
| 이벤트 이름 | 인터페이스 | 디스패치되는 시점... | 전제 조건 |
|---|---|---|---|
encrypted
|
MediaEncryptedEvent
|
사용자 에이전트가 초기화 데이터를 미디어 데이터에서 만난다. |
요소의 readyState가
HAVE_METADATA와
같거나 그보다 크다.
주
요소가 재생 중이거나 재생된 적이 있을 수 있다. |
waitingforkey
|
Event
|
키를 기다리느라 재생이 차단된다. |
readyState가
HAVE_CURRENT_DATA와
같거나 그보다 작다.
요소의 playback blocked waiting
for key 값이 새롭게 true가 된다.
|
미디어 데이터가 암호화된 블록을 포함할 수 있음 알고리즘은 사용자 에이전트가 미디어 데이터를
재생하기 전에 MediaKeys 객체의 지정을
요구하는 경우 재생을 일시 중지한다.
이 알고리즘을 실행하라는 요청에는 대상 HTMLMediaElement 객체가 포함된다.
다음 단계가 실행된다:
media element를 지정된 HTMLMediaElement 객체로 둔다.
media element의 mediaKeys 속성이 null이고
구현이 잠재적으로 암호화된 미디어 데이터를
디코딩하기 전에 MediaKeys 객체의 지정을
요구하면,
다음 단계를 실행한다:
애플리케이션이 setMediaKeys()를
호출하여 MediaKeys 객체를
제공하기 전에 미디어 데이터를
제공하면 이 단계에 도달할 수 있다. CDM 선택은 사용되는 파이프라인 및/또는 디코더에
영향을 줄 수 있으므로, 일부 구현은
MediaKeys 객체를
setMediaKeys()에
전달하여 CDM이 지정될 때까지
암호화된 블록을 포함할 수 있는 미디어 데이터의 재생을 지연시킬 수 있다.
media element에 대해 키 대기 알고리즘을 실행한다.
재생을 재개하라는 신호를 기다린다.
초기화 데이터 발견 알고리즘은 미디어 데이터에서 만난
초기화 데이터에 대한
이벤트를 큐에 넣는다.
이 알고리즘을 실행하라는 요청에는 대상 encryptedHTMLMediaElement 객체가 포함된다.
다음 단계가 실행된다:
media element를 지정된 HTMLMediaElement 객체로 둔다.
initDataType을 빈 문자열로 둔다.
initData를 null로 둔다.
미디어 데이터가 CORS-same-origin이고 혼합 콘텐츠가 아니면, 다음 단계들을 실행한다.
initDataType을 초기화 데이터의 초기화 데이터 유형을 나타내는 문자열로 둔다.
initData를 초기화 데이터로 둔다.
미디어 요소가 "Upgradeable Content" [MIXED-CONTENT]의 로드를 허용할 수는 있지만, 사용자 에이전트는 그러한 미디어 데이터의 초기화 데이터를 애플리케이션에 노출해서는 MUST NOT 된다.
태스크를
큐에 넣어 버블링하지 않고 취소할 수 없는 라는 이름의 이벤트를 생성한다.
이 이벤트는 encryptedMediaEncryptedEvent 인터페이스를 사용하며,
그
type 속성은 encrypted로 설정되고
isTrusted 속성은 true로 초기화되며,
이를 media element에 디스패치한다.
이벤트 인터페이스 MediaEncryptedEvent는 다음을 가진다.
initDataType =
initDataTypeinitData =
initData
readyState는
변경되지 않고 어떤 알고리즘도
중단되지 않는다. 이 이벤트는 단지 정보를 제공할 뿐이다.
미디어 데이터가 CORS-same-origin이
아니거나 혼합 콘텐츠인 경우,
initData 속성은
null이 된다. 애플리케이션은 다른
소스에서 초기화 데이터를 가져올 수 있다.
암호화된 블록 발견 알고리즘은 암호화된 미디어 데이터 블록을 복호화용으로 큐에 넣고,
가능하면 복호화를 시도한다. 이 알고리즘을 실행하라는 요청에는 대상
HTMLMediaElement
객체가 포함된다.
다음 단계가 실행된다:
media element를 지정된 HTMLMediaElement 객체로 둔다.
block을 암호화된 미디어 데이터 블록으로 둔다.
block을 media element의 encrypted block queue 끝에 추가한다.
media element의 decryption blocked waiting for key
값이 false이면, 복호화 시도 알고리즘을 실행한다.
복호화 시도 알고리즘은 복호화용으로 큐에 들어간 미디어 데이터를 복호화하려고 시도한다.
이 알고리즘을 실행하라는 요청에는 대상 HTMLMediaElement
객체가 포함된다.
다음 단계가 실행된다:
media element를 지정된 HTMLMediaElement 객체로 둔다.
media element의 encrypted block queue가 비어 있으면, 이 단계를 중단한다.
media element의 mediaKeys 속성이
null이 아니면, 다음 단계를 실행한다:
media keys를 그 속성이 참조하는
MediaKeys 객체로
둔다.
cdm을 media keys의 cdm instance 값이 나타내는 CDM 인스턴스로 둔다.
cdm을 어떤 이유로든 더 이상 사용할 수 없으면, 다음 단계를 실행한다:
리소스 가져오기 알고리즘의 미디어 데이터가 손상됨 단계를 실행한다.
media keys에 대해
CDM
사용 불가 알고리즘을 실행하며, 이유로 하드웨어 컨텍스트
재설정의 경우
"hardware-context-reset",
그렇지 않으면 "internal-error"를
사용한다.
이 단계를 중단한다.
media
keys가 생성한 MediaKeySession 중
닫힌 상태가 아닌 것이
적어도 하나 있으면, 다음 단계를 실행한다:
이 검사는 cdm의 로드가 완료되었음을 보장하며, 일치하는 키가 사용 가능하기 위한 전제조건이다.
block을 media element의 encrypted block queue 안의 첫 번째 항목으로 둔다.
block key ID를 block의 키 ID로 둔다.
키 ID는 일반적으로 컨테이너가 지정한다.
cdm을 사용하여 다음 단계를 실행한다:
available keys를 media keys가 생성한 세션 안의 키들의 합집합으로 둔다.
block key를 null로 둔다.
available keys 중 하나라도 block
key ID에 대응하고 복호화에 사용할 수
있으면, session을 그 키를 포함하는
MediaKeySession
객체로 두고, block
key를 그 키로 둔다.
여러 세션이 block key ID에 대해 복호화에 사용할 수 있는 키를 포함하는 경우, 사용할 세션과 키는 키 시스템에 따라 다르다.
앞의 단계를 실행한 결과 available keys 중 하나의
상태가 변경되었으면, 영향을 받은 각 session에 대해
태스크를
큐에 넣어
키 상태
갱신
알고리즘을 실행하고, 세션 안의 모든
키
ID와
각 키에 대한 적절한
MediaKeyStatus
값을 제공한다.
block key가 null이 아니면, 다음 단계를 실행한다:
cdm을 사용하여 block key로 block을 복호화한다.
다음 목록에서 첫 번째로 일치하는 조건에 대한 단계를 따른다:
미디어 데이터가 손상됨 단계를 리소스 가져오기 알고리즘에서 실행한다.
cdm을 더 이상 사용할 수 없으면,
media
keys에 대해
CDM
사용 불가 알고리즘을 실행하며,
이유로 하드웨어 컨텍스트 재설정의 경우
"hardware-context-reset",
그렇지 않으면
"internal-error"를
사용한다.
이 단계를 중단한다.
media element의 encrypted block queue 앞에서 block을 제거한다.
복호화된 블록을 정상적으로 처리한다.
다시 말해, 블록을 디코딩한다.
이 알고리즘의 처음으로 돌아간다.
모든 복호화 문제(예: 잘못된 키 사용)가 복호화 실패를 초래하는 것은 아니다. 그런 경우 여기에서는 오류가 발생하지 않지만, 디코딩 중에 발생할 수 있다.
그렇지 않으면, 어떤 세션에도 block key ID에 대한 키가 없으므로 계속한다.
media element의 decryption blocked waiting for key
값을 true로 설정한다.
이 단계에는 block에 대해 복호화에 사용할 수 있는 키가 없을 때 도달한다.
사용자 에이전트가 복호화할 수 없는 블록보다 앞에 있는 블록들을 렌더링한 뒤 (예를 들어 모든 완전한 비디오 프레임처럼 가능한 만큼), 키 대기 알고리즘을 실행한다.
그 알고리즘은 현재 재생 위치보다 앞선 미디어 데이터를 구현이 복호화하고 디코딩할 수 있게 하면서도 보이는 동작에 영향을 주지 않도록 하기 위해 여기에서 직접 실행되지 않는다.
프레임 기반 암호화의 경우, 미디어 요소가 리소스 가져오기 알고리즘의 일부로 프레임을 디코딩하려고 시도할 때 다음과 같이 구현될 수 있다:
encrypted를 false로 둔다.
프레임이 암호화되었는지 감지한다.
프레임을 디코딩한다.
렌더링을 위해 프레임을 제공한다.
키 대기 알고리즘은
이벤트를 큐에 넣고
waitingforkeyreadyState를
갱신한다.
이 알고리즘은 HTMLMediaElement
객체가 잠재적으로
재생 중이고 그 readyState가
HAVE_FUTURE_DATA와
같거나 그보다 클 때에만 호출되어야 한다. 이 알고리즘을 실행하라는 요청에는 대상
HTMLMediaElement 객체가 포함된다.
다음 단계가 실행된다:
media element를 지정된 HTMLMediaElement 객체로 둔다.
media element의 playback blocked waiting for key 값이
true이면, 이 단계를 중단한다.
media element의 playback blocked waiting for key
값을 true로 설정한다.
위 단계의 결과로, 미디어 요소가 아직 차단된 미디어 요소가 아니었다면 그렇게 된다. 그 경우, 미디어 요소는 재생을 중지한다.
다음 목록에서 첫 번째로 일치하는 조건에 대한 단계를 따른다:
media element의
readyState를
HAVE_CURRENT_DATA로
설정한다.
media element의
readyState를
HAVE_METADATA로
설정한다.
다시 말해, 현재
재생 위치에 대한 비디오 프레임과 오디오 데이터가 암호화되지 않았거나
성공적으로 복호화되었기 때문에 디코딩되었다면,
readyState를
HAVE_CURRENT_DATA로
설정한다.
그렇지 않으면, 이전에 그러한 상태였지만 데이터를 더 이상 사용할 수 없는 경우를
포함하여, readyState를
HAVE_METADATA로
설정한다.
media
element에서 라는 이름의
이벤트를 발화하도록
태스크를
큐에 넣는다.
waitingforkey
재생을 일시 중지한다.
필요하면 재생 재개 시도 알고리즘은 미디어 요소가 키를 기다리느라 차단되어 있고 필요한 키를
현재 복호화에 사용할 수 있으면 재생을 재개한다.
이 알고리즘을 실행하라는 요청에는 대상 HTMLMediaElement
객체가 포함된다.
다음 단계가 실행된다:
media element를 지정된 HTMLMediaElement 객체로 둔다.
media element의 playback blocked waiting for key가
false이면, 이 단계를 중단한다.
media element에 대해 복호화 시도 알고리즘을 실행한다.
사용자 에이전트가 현재 재생 위치를 재생 방향으로 진행시킬 수 있으면:
media element의 decryption blocked waiting for
key 값을 false로 설정한다.
media element의 playback blocked waiting for key
값을 false로 설정한다.
위 단계의 결과로, 미디어 요소는 더 이상 차단된 미디어 요소가 아닐 수 있으며, 따라서 재생이 재개될 수 있다.
media element의 readyState
값을 적절한 대로
HAVE_CURRENT_DATA,
HAVE_FUTURE_DATA
또는 HAVE_ENOUGH_DATA로
설정한다.
HAVE_CURRENT_DATA를
넘는 상태와
canplaythrough
이벤트는 현재 키를 넘어선 키 사용 가능성을 고려하지 않는다(또는 그럴
가능성이 낮다).
준비 상태의 변경은 또한 HTMLMediaElement
이벤트가 여기에
설명된 대로 발화되도록 할 수 있다.
이 절은 비규범적이다.
CDM이
처리한 미디어 데이터는 일반적인 방식으로 웹 플랫폼
API를 통해 사용할 수 없을 수 있다 MAY
(예를 들어 CanvasRenderingContext2D
drawImage()
메서드와 AudioContext
MediaElementAudioSourceNode를
사용하는 경우).
이 명세는 그러한 미디어 데이터의 비가용성에 대한 조건을 정의하지 않는다. 그러나 그러한
API를 통해 미디어 데이터를 사용할 수 없다면, 해당 API는 미디어 데이터가 전혀 없는 것처럼
동작할 수 있다 MAY.
미디어 렌더링이 UA에 의해 수행되지 않는 경우, 예를 들어 하드웨어 기반 미디어 파이프라인의 경우에는, CSS Transforms와 같은 HTML 렌더링 기능 전체 집합을 사용할 수 없을 수 있다 MAY. 한 가지 가능한 제한은 비디오 미디어가 창의 가장자리와 평행한 변을 가진 직사각형 영역 안에 정상 방향으로만 나타나도록 제한될 수 있다는 것이다 MAY.
이 절은 사용자 에이전트와 키 시스템 모두에 대한 구현 요구사항을 정의한다. 여기에는 CDM 및 서버가 포함되며, 이러한 요구사항은 알고리즘에서 명시적으로 다루지 않을 수 있다. 여기 및 명세 전반의 요구사항은 CDM이 사용자 에이전트와 분리되어 있는지 또는 사용자 에이전트의 일부인지와 관계없이 모든 구현에 적용된다.
사용자 에이전트 구현자는 CDM이 이 명세의 기능을 사용하여 보호된 미디어를 재생하는 데 합리적으로 필요하지 않은 정보, 저장소 또는 시스템 기능에 접근하지 않도록 보장해야 MUST 한다. 구체적으로, CDM은 다음을 해서는 SHALL NOT 안 된다.
이 명세에서 명시적으로 허용한 대로 사용자 에이전트를 통하는 경우를 제외하고, 로컬 또는 원격 네트워크 리소스에 접근하는 것.
이 명세의 기능을 사용하여 보호된 미디어를 재생하는 데 합리적으로 필요한 경우를 제외하고, 저장소(예: 디스크 또는 메모리)에 접근하는 것.
이 명세의 기능을 사용하여 보호된 미디어를 재생하는 데 합리적으로 필요한 경우를 제외하고, 하드웨어 구성요소 또는 장치에 접근하는 것.
사용자 에이전트 구현자는 위 요구사항을 충족하기 위해 다양한 기법을 사용할 수 있다. 예를 들어, 자체 CDM도 구현하는 사용자 에이전트 구현자는 위 내용을 해당 구성요소의 설계 요구사항으로 포함할 수 있다. 제3자 CDM을 사용하는 사용자 에이전트 구현자는 금지된 정보와 구성요소에 접근할 수 없는 제한된 환경(예: "sandbox")에서 실행되도록 보장할 수 있다.
CDM과 주고받는 모든 메시지와 통신, 예를 들어 CDM과 라이선스 서버 사이의 통신은 사용자 에이전트를 통해 전달되어야 MUST 한다. CDM은 직접적인 대역 외 네트워크 요청을 해서는 MUST NOT 된다. 직접 개별화에 설명된 것 이외의 모든 메시지와 통신은 이 명세에 정의된 API를 통해 애플리케이션을 거쳐 전달되어야 MUST 한다. 구체적으로, 애플리케이션별, 출처별, 또는 콘텐츠별 정보를 포함하거나 애플리케이션이 지정한 URL 또는 그 출처에 기반한 URL로 전송되는 모든 통신은 API를 거쳐야 MUST 한다. 여기에는 모든 라이선스 교환 메시지가 포함된다.
지속 데이터에는 CDM이 저장하거나, CDM을 대신하여 사용자 에이전트가 저장한 모든 데이터 중
MediaKeys 객체의 폐기 후에도 존재하는 데이터가 포함된다.
구체적으로, 여기에는 CDM이 저장하거나
CDM을
대신하여 사용자 에이전트가 저장한
모든 식별자(고유 식별자 포함),
라이선스, 키, 키 ID, 또는 라이선스 폐기 기록이 포함된다.
애플리케이션 또는 라이선스 서버에서 볼 수 있는 방식으로 메시지나 동작에 영향을 줄 수 있는 영속 데이터는 출처별 및 브라우징 프로필별 방식으로 저장되어야 MUST 하며, 비공개 브라우징 세션으로 유출되거나 거기에서 유출되어서는 안 된다 MUST NOT. 구체적으로 그러나 이것에 국한되지 않고, 세션 데이터, 라이선스, 키 및 출처별 식별자는 출처별 및 브라우징 프로필별로 저장되어야 MUST 한다.
세션 저장소 및 영속성을 참고한다.
영속 데이터를 사용하는 구현은 이 명세에 정의된 API와 같은 외부와 클라이언트 장치 양쪽에서 해당 데이터를 더 이상 가져올 수 없도록 사용자가 그 데이터를 지울 수 있게 해야 MUST 한다.
사용자 에이전트는 다음을 하는 것이 좋다 SHOULD:
영속 데이터를 쿠키 [COOKIES] 같은 다른 사이트 데이터처럼 취급한다. 구체적으로:
사용자가 브라우징 기록을 지우는 사용자 에이전트 기능의 일부로 영속 데이터를 지울 수 있도록 허용한다.
"모든 데이터 제거" 기능에 영속 데이터를 포함한다.
영속 데이터를 다른 사이트 데이터와 같은 UI 위치에 표시한다.
사용자가 출처별 및 브라우징 프로필별 기준으로 영속 데이터를 지울 수 있도록 허용한다. 특히 특정 사이트와 연결된 쿠키 [COOKIES], 데이터베이스 등을 잊는 "이 사이트 잊기" 기능의 일부로 허용한다.
영속 데이터를 지우는 작업이, 동시에 지워지지 않은 다른 종류의 로컬 저장 데이터를 이용하여 새 식별자를 이전 식별자와 다시 상관시키는 "쿠키 부활" 유형의 재상관을 방지할 만큼 충분히 원자적이도록 보장한다. 데이터의 불완전한 삭제를 참고한다.
사용자가 데이터의 불완전한 삭제 가능성을 이해하는 데 도움이 되고, 쿠키 [COOKIES] 및 웹 저장소를 포함하여 데이터를 영속화하는 모든 기능과 연결된 데이터를 동시에 삭제할 수 있도록 하는 방식으로 이러한 인터페이스를 제시한다.
키 시스템을 비활성화하고 다시 활성화하는 인터페이스를, 사용자가 데이터의 불완전한 삭제 가능성을 이해하는 데 도움이 되고 모든 영속 저장 기능에서 그러한 모든 데이터를 동시에 삭제할 수 있도록 하는 방식으로 제시한다.
사용자가 출처별 및/또는 모든 출처에 대해 영속 데이터를 구체적으로 삭제할 수 있도록 허용한다.
사용자 에이전트는 영속 데이터를 잠재적으로 민감한 것으로 취급하는 것이 좋다 SHOULD. 이 정보의 공개로 인해 사용자 개인정보가 침해될 가능성은 충분히 있다. 이를 위해 사용자 에이전트는 영속 데이터가 안전하게 저장되도록 보장하고, 데이터를 삭제할 때에는 기반 저장소에서 즉시 삭제되도록 보장하는 것이 좋다 SHOULD.
애플리케이션에 노출되거나, 예를 들어 CDM의 사용을 통해 추론 가능한 값은 식별자로 설계되었는지 여부와 관계없이 클라이언트 또는 사용자를 식별하는 데 사용될 수 있다. 이 절은 그러한 우려를 피하거나 적어도 완화하기 위한 요구사항을 정의한다. 식별자에 대해서는 추가 요구사항이 있다.
애플리케이션에 노출되거나 추론 가능한 모든 구별 값은 출처 및 브라우징 프로필마다 고유해야 MUST 한다. 즉, 이 명세에 정의된 API를 사용하는 한 출처에 대해 사용되는 값은 API를 사용하는 다른 어떤 출처에 대해 사용되는 값과도 달라야 MUST 하며, 한 브라우징 프로필에서 사용되는 값은 출처와 관계없이 다른 어떤 프로필에서 사용되는 값과도 달라야 MUST 한다. 그러한 값은 비공개 브라우징 세션으로 유출되거나 거기에서 유출되어서는 안 된다 MUST NOT.
출처와 프로필 간의 값은 애플리케이션에 의해 연관될 수 없어야 MUST 한다. 이는 같은 클라이언트 또는 사용자에서 왔음을 판단하는 등 여러 출처 또는 프로필의 값을 상관시킬 수 없어야 MUST NOT 함을 의미한다. 구체적으로, 출처별 값을 출처 독립적 및/또는 프로필 독립적 값에서 도출하는 구현은 적절한 비가역 속성을 가진 도출 함수를 사용하는 등, 위의 비연관성 속성을 보장하는 방식으로 그렇게 해야 MUST 한다.
영속 데이터를 지울 수 있도록 허용의 요구사항의 결과로, 애플리케이션에 노출되는 모든 영속화된 값은 이 명세에 정의된 API와 같은 외부와 클라이언트 장치 양쪽에서 더 이상 가져오거나, 관찰하거나, 추론할 수 없도록 지울 수 있어야 MUST 한다.
일단 지워지면, 이후 값이 필요할 때 새 애플리케이션에 의해 연관될 수 없는 값이 생성되어야 MUST 한다.
구현에서 식별자, 특히 구별 식별자 또는 구별 영구 식별자를 사용하는 것은 개인정보 보호 문제를 제기한다. 이 절은 그러한 우려를 피하거나 적어도 완화하기 위한 요구사항을 정의한다. 애플리케이션에 노출되는 값에 대한 요구사항도 애플리케이션에 노출되는 식별자에 적용된다.
구현은 구별 식별자 또는 구별 영구 식별자의 사용을 피하는 것이 좋다 SHOULD.
예를 들어, 개별 클라이언트가 아니라 클라이언트 또는 장치 그룹에 적용되는 식별자나 다른 값을 사용한다.
구현은 특정 CDM 인스턴스 및 세션과 관련된 정책을 적용하는 데 필요한 경우에만 구별 식별자 또는 구별 영구 식별자를 사용하는 것이 좋다 SHOULD.
예를 들어, "temporary" 및
"persistent-license"
세션은 서로 다른 요구사항을 가질 수 있다.
구별 식별자 또는 구별 영구 식별자를 사용하는 구현은 이를 사용하지 않는 옵션을 지원하는 것이 좋다 SHOULD. 그러한 지원을 가진 구현은 사용자가 이 옵션을 선택할 수 있는 기능을 노출하는 것이 좋다 SHOULD.
지원되는 경우, 애플리케이션은
distinctiveIdentifier
=
"not-allowed"를
사용하여 이 모드를 선택할 수 있다.
이러한 옵션을 선택하면
requestMediaKeySystemAccess()
호출의 결과 및/또는 이후 생성된 세션에서 생성되는 라이선스 요청에 영향을 줄 수 있다.
사용자가 이 구현 기능을 선택하거나 고를 수 있게 하면, 사용자는 더 높은 수준의 개인정보 보호를 유지하면서 콘텐츠에 접근할 수 있을 수 있다.
고유 식별자와 고유 영구 식별자는 클라이언트 외부에 노출될 때 메시지 교환 수준에서 암호화되어야 MUST 한다. 다른 모든 식별자는 클라이언트 외부에 노출될 때 메시지 교환 수준에서 암호화되는 것이 SHOULD 된다. 암호화는 식별자 암호문의 임의의 두 인스턴스가 복호화 키를 소유한 엔터티에 의해서만 연관 가능하도록 보장해야 MUST 한다.
CDM은 암호화 키가 해당 키 시스템의 유효한 서버에 속하는지 검증해야 MUST 한다. 애플리케이션에 노출되는 식별자의 경우, 이는 서버 인증서를 사용하여 구현될 MAY 있다.
구별 영구 식별자를 제외한 모든 식별자는 출처 및 브라우징 프로필마다 고유해야 MUST 한다. 8.4.1 출처별 프로필별 값 사용을 참고한다.
구현이 애플리케이션에 노출하는 모든 식별자, 암호화된 형태의 식별자까지 포함하여 구별 식별자는 출처, 브라우징 프로필 및 식별자 삭제 전후에 걸쳐 애플리케이션에 의해 연관될 수 없어야 MUST 한다.
지속 데이터를 삭제할 수 있도록 허용의 요구사항의 결과로, 고유 영구 식별자를 제외한 모든 잠재적 식별자 또는 고유 식별성 값은 이 명세에 정의된 API를 통해서와 같은 외부와 클라이언트 장치 양쪽 모두에서 해당 값을 더 이상 검색, 관찰 또는 추론할 수 없도록 삭제 가능해야 MUST 한다.
고유 식별자를 사용하는 구현은 사용자가 고유 식별자를 삭제할 수 있도록 해야 MUST 한다. 고유 영구 식별자를 사용하는 구현은 사용자가 고유 영구 식별자와 연결된 값을 삭제할 수 있도록 해야 MUST 한다.
삭제된 후에는 이후에 고유 식별자와 같은 값이 필요할 때 새로운 애플리케이션에 의해 연관 불가능한 값을 생성해야 MUST 한다.
식별자, 특히 고유 식별자는 때때로 개별화 또는 프로비저닝이라고 하는 프로세스를 통해 생성되거나 얻어진다. 그 결과로 생성된 식별자는 애플리케이션에 의해 연관 불가능해야 MUST 하며, 그 사용은 단일 프로필의 단일 출처에만 노출되어야 MUST 한다. 이 프로세스는 식별자가 삭제된 뒤와 같이 여러 번 수행될 MAY 수 있다.
이 프로세스는 사용자 에이전트가 직접 또는 애플리케이션을 통해 수행되어야 MUST 한다. 두 유형의 개별화에 대한 메커니즘, 흐름 및 제한은 다음 절에 설명된 것처럼 서로 다르다. 어떤 방법이 사용되는지는 CDM 구현 및 이 명세의 요구사항, 특히 아래 요구사항의 적용에 따라 달라진다.
distinctiveIdentifier는
고유 식별자와
고유 영구
식별자가 개별화를 포함하여 사용될 수
있는지를 제어한다. 구체적으로, 그러한 식별자는
distinctiveIdentifier
멤버의 값이, MediaKeySystemAccess를 사용해 생성한
MediaKeys 객체에서
"required"일 때만 사용될 수
있다.
직접 개별화는 CDM과 출처 및 애플리케이션에 독립적인 서버 사이에서 수행된다. 서버는 출처에 독립적이지만, 개별화의 결과를 통해 CDM은 이 명세의 다른 요구사항에 따라 출처별 식별자를 제공할 수 있다. 이 프로세스는 사용자 에이전트가 수행해야 MUST 하며, 이 명세에 정의된 API를 사용해서는 MUST NOT 된다.
예를 들어, 그러한 프로세스는 사용자 에이전트 또는 CDM 공급업체가 호스팅하는 미리 정해진 서버와 통신하여 클라이언트 장치를 초기화하거나 및/또는 단일 브라우징 프로필에 대해 출처별 삭제 가능한 식별자를 얻을 수 있으며, 이때 클라이언트 장치의 고유 영구 식별자 사용 또는 기타 영구 식별자를 사용할 수도 있다.
그러한 개별화의 경우, 모든 메시지 교환은:
사용자 에이전트가 처리하고 사용자 에이전트의 네트워크 스택을 통해 사용자 에이전트가 수행해야 MUST 한다.
CDM이 직접 수행해서는 MUST NOT 된다.
이 명세에 정의된 API를 통해 애플리케이션으로 전달되거나 애플리케이션을 거쳐 전달되어서는 MUST NOT 된다.
어떤 출처와 애플리케이션에도 독립적으로 선택된 URL로 전송되어야 MUST 한다.
TLS를 사용해야 MUST 한다.
구현은 암호화된 형태로라도 출처, 출처 또는 애플리케이션별 정보, 또는 출처와 연관 가능한 값을 중앙 서버에 노출해서는 MUST NOT 된다. 이는 사용자 또는 장치가 방문한 모든 출처의 중앙 기록을 생성할 수 있기 때문이다.
애플리케이션 보조 개별화는 CDM과 애플리케이션, 애플리케이션이 선택한 서버를 포함한 대상 사이에서 수행되며, 출처별 식별자를 생성한다. 이 프로세스는 이 명세에 정의된 API를 통해 수행되어야 MUST 하며, 다른 통신 방법을 포함해서는 MUST NOT 된다. API의 다른 모든 사용과 마찬가지로, 이 프로세스는 하나 이상의 고유 식별자를 사용할 MAY 수 있지만, 암호화된 형태로라도 고유 영구 식별자를 사용하거나 출처별이 아닌 값을 사용해서는 MUST NOT 된다. 이 프로세스가 하나 이상의 고유 식별자를 사용하는 경우, 결과 식별자도 정의상 고유 식별자이다.
그러한 개별화의 경우, 모든 메시지 교환은:
이 명세에 정의된 API를 통해 애플리케이션으로 전달되거나 애플리케이션을 거쳐 전달되어야 MUST 한다.
관련된 모든
이벤트에 대해 메시지 유형 "messageindividualization-request"를
사용해야 SHALL 한다.
사용자 에이전트가 수행해서는 MUST NOT 된다.
CDM이 직접 수행해서는 MUST NOT 된다.
고유 영구 식별자를 사용하거나 포함해서는 MUST NOT 된다.
출처별이 아닌 클라이언트별 정보를 포함해서는 MUST NOT 된다.
식별자 요구사항을 준수해야 MUST 한다.
여기에는 출처 및 프로필별로 고유하고 삭제 가능한 값만 사용하며, 요구되는 대로 이를 암호화하는 것이 포함된다.
CDM에 실행 가능한 코드를 제공해서는 MUST NOT 된다.
고유 식별자를 포함한 연관 가능한 값이 이 프로세스에서 사용되는 경우, 구현은 암호화된 형태로라도 출처, 출처 또는 애플리케이션별 정보, 또는 출처와 연관 가능한 값을 중앙 서버에 노출해서는 MUST NOT 된다. 이는 사용자 또는 장치가 방문한 모든 출처의 중앙 기록을 생성할 수 있기 때문이다.
적절한 예방 조치를 취하면, 그러한 개별화는 직접 개별화보다 더 나은 개인정보 보호를 제공할 수 있지만, 고유 식별자를 사용하지 않는 모델만큼 좋지는 않다. 그러한 설계의 이점을 보존하고 다른 개인정보 보호 우려를 도입하지 않기 위해, 그러한 구현 및 이를 지원하는 애플리케이션은 개별화 메시지를 중앙 서버 또는 애플리케이션 작성자가 제어하지 않는 다른 서버로 연기하거나 전달하는 것을 피하는 것이 SHOULD 된다.
구현은 각 MediaKeySession 객체 안에서 여러 키를
지원해야 MUST 한다.
여러 키가 지원되는 방식의 메커니즘은 구현 세부사항이지만, 애플리케이션과 이 명세에 정의된 API에는 투명해야 MUST 한다.
구현은 재생 중 키 간의 끊김 없는 전환을 지원해야 MUST 한다.
여기에는 같은 MediaKeySession 안의 키와 별도의
MediaKeySession 객체 안의 키 모두가 포함된다.
구현은 지원하는 어떤 초기화 데이터 타입으로 생성된 라이선스든 어떤 콘텐츠 타입과도 함께 사용할 수 있도록 허용하는 것이 좋다 SHOULD.
그렇지 않으면, 예를 들어
requestMediaKeySystemAccess()
알고리즘은
MediaKeySystemConfiguration을
거부할 수 있다. 그 이유는
initDataTypes
중 하나가
videoCapabilities
중 하나와 함께 지원되지 않기 때문일 수 있다.
지원되는 컨테이너에 나타날 수 있는 지원되는 초기화 데이터 타입에 대해, 사용자 에이전트는 그러한 각 지원 컨테이너에서 그 타입의 초기화 데이터를 추출하는 것을 지원해야 MUST 한다.
다시 말해, 초기화 데이터 타입 지원을 나타내는 것은 라이선스 요청 생성을 위한 CDM 지원과, 컨테이너별 타입의 경우 이를 컨테이너에서 추출하기 위한 사용자 에이전트 지원을 모두 의미한다. 이는 구현이 임의의 지원되는 초기화 데이터를 임의의 지원되는 콘텐츠 타입에서 파싱할 수 있어야 함을 의미하지는 않는다.
이 절은 이 명세의 구현에서 지원되는 콘텐츠(미디어 리소스)의 속성을 정의한다.
미디어 컨테이너는 암호화되어서는 안 된다 MUST NOT. 이 명세는
사용자 에이전트가 미디어 데이터의 어느 것도 복호화하지 않고 미디어 컨테이너를 파싱할 수
있는 능력에 의존한다. 여기에는 암호화된 블록 발견 및
초기화 데이터 발견
알고리즘뿐 아니라 HTMLMediaElement
[HTML]의
표준 기능, 예를 들어 탐색 지원도
포함된다.
모든 트랙을 포함한 미디어 리소스는 컨테이너별 "common encryption" 명세에 따라 암호화되고 패키징되어야 MUST 하며, 해당 명세는 하나 이상의 키가 제공될 때 콘텐츠가 완전히 명시되고 호환 가능한 방식으로 복호화될 수 있도록 해야 한다.
암호화된 미디어 확장 스트림 형식 레지스트리는 그러한 스트림 형식에 대한 참조를 제공한다.
캡션, 해설 오디오, 대본과 같은 인밴드 지원 콘텐츠는 암호화하지 않는 것이 좋다 SHOULD NOT.
그러한 트랙의 복호화, 특히 이를 사용자 에이전트에 다시 제공할 수 있게 하는 복호화는 일반적으로 구현에서 지원되지 않는다. 따라서 그러한 트랙을 암호화하면 사용자 에이전트 구현의 접근성 기능에서 널리 사용할 수 없게 된다.
접근성 정보가 사용 가능한 형태로 제공되도록 보장하기 위해, 암호화된 인밴드 지원 콘텐츠를 지원하기로 선택한 구현의 경우: a) CDM은 복호화된 데이터를 사용자 에이전트에 제공해야 MUST 하고, b) 사용자 에이전트는 이를 예를 들어 timed text tracks [HTML]로 노출하기 위해, 동등한 암호화되지 않은 지원 콘텐츠와 같은 방식으로 처리해야 MUST 한다.
모든 사용자 에이전트는 이 절에서 설명하는 공통 키 시스템을 지원해야 MUST 한다.
이는 완전히 오픈 소스인 사용자 에이전트를 포함하여 모든 사용자 에이전트에서 지원이 보장되는 공통 기준 수준의 기능이 존재하도록 보장한다. 따라서 기본 복호화만 필요한 콘텐츠 제공자는 어떤 콘텐츠 보호 제공자와도 협력할 필요 없이 모든 플랫폼에서 동작하는 단순한 애플리케이션을 만들 수 있다.
"org.w3.clearkey" 키 시스템은 소스를 복호화하기 위해
평문 clear(암호화되지 않은) 키를 사용한다. 추가적인 클라이언트 측 콘텐츠 보호는 요구되지 않는다.
이 키 시스템은 아래에 설명되어 있다.
다음은 Clear Key가 키 시스템별 기능을 지원하는 방식을 설명한다:
encryptionScheme:
구현은
스킴을 지원해야 MUST 하며, 다른 스킴을 지원할 수 있다
MAY.
"cenc"
robustness:
빈 문자열만 지원된다.
distinctiveIdentifier:
"required"는
지원되지 않는다.
persistentState:
애플리케이션이 지원되는 경우
"temporary"가
아닌 세션을 만들 의도가 없다면
"required"가
아니다.
"persistent-license"
MediaKeySessionType:
구현은 이 타입을 지원할 수 있다 MAY.
setServerCertificate()
메서드: 지원되지 않는다.
getStatusForPolicy()
메서드: 구현은 항상
"usable"로
프로미스를 이행하는 것이 좋다.
setMediaKeys()
메서드: 구현은 MediaKeys 객체를
둘 이상의 HTMLMediaElement와 연결하는 것을
지원할 수 있다 MAY.
다음은 Clear Key가 키 시스템별 동작을 구현하는 방식을 설명한다:
generateRequest()
알고리즘에서:
생성된 message는 라이선스 요청 형식에 설명된 대로 UTF-8로 인코딩된 JSON 객체이다.
요청은 sanitized init data에서 키 ID를 추출하여 생성된다.
"type" 멤버 값은 sessionType 매개변수의 값이다.
sessionId 속성은
32비트 정수로 표현 가능한 수치 값이다.
expiration 속성은
항상 NaN이다.
update()
알고리즘에서:
response 매개변수는 라이선스 형식에 설명된 JWK Set이거나, 라이선스 릴리스 확인 형식에 설명된 UTF-8로 인코딩된 JSON 객체이다.
첫 번째 경우, sanitized response는 오디오/비디오 타입에 대해 유효한 길이의 유효한 JWK 키를 하나 이상 가진 유효한 JWK Set이 아니면 유효하지 않은 것으로 간주된다. 두 번째 경우 sanitized response는 유효한 JSON 객체가 아니면 유효하지 않은 것으로 간주된다.
"persistent-license"
타입의 세션의 경우,
remove()
알고리즘에서, record of license destruction을 반영하는
message는 라이선스 릴리스 형식에
설명된 대로 UTF-8로 인코딩된 JSON 객체이다.
keyStatuses 속성
메서드는 처음에는 update()를 통해
제공된 모든 키 ID를 포함하며, 상태는
"usable"이다.
remove()
알고리즘이 실행되면, keyStatuses 속성은 빈
목록으로 설정된다.
초기화 데이터: 구현은 등록된
초기화 데이터 타입 [EME-INITDATA-REGISTRY]의
어떤 조합이든 지원할 수 있다 MAY.
구현은 "keyids" 타입 [EME-INITDATA-KEYIDS]과
사용자 에이전트가 지원하는 콘텐츠 타입에 적합한 다른 타입을 지원하는 것이 좋다
SHOULD.
이 절은 이벤트의
message 속성을 통해 애플리케이션에 제공되는 라이선스 요청의 형식을 설명한다.
message
이 형식은 다음 멤버를 포함하는 JSON 객체이다:
MediaKeySessionType.
MediaKeyMessageEvent 객체의
ArrayBuffer message
속성에 포함될 때, JSON 문자열은 Encoding 명세 [ENCODING]에 명시된 대로 UTF-8로 인코딩된다.
애플리케이션은 TextDecoder 인터페이스
[ENCODING]를 사용하여 ArrayBuffer의 내용을 JSON
문자열로 디코딩할 수 있다 MAY.
이 절은 비규범적이다.
다음 예제는 두 개의 키 ID에 대한 임시 라이선스의 라이선스 요청이다. (줄바꿈은 읽기 쉽도록 하기 위한 것일 뿐이다.)
{
"kids": [
"LwVHf8JLtPrv2GUXFW2v_A",
"0DdtU9od-Bh5L3xbv0Xf_A"
],
"type": "temporary"
}
이 절은 update() 메서드의
response 매개변수를 통해 제공될 라이선스의 형식을 설명한다.
이 형식은 JSON Web Key (JWK) 명세 [RFC7517]에 정의된 대로 복호화에 사용할 대칭 키의 표현을 포함하는 JSON Web Key (JWK) Set이다.
집합의 각 JWK에 대해, 매개변수 값은 다음과 같다:
JSON 객체는 선택적인 "type" 멤버 값을 가질 수 있으며 MAY,
이는 MediaKeySessionType
값 중 하나여야 MUST 한다. 지정되지 않으면 기본값
"temporary"가 사용된다.
update() 알고리즘은
이 값을 sessionType과 비교한다.
update() 메서드에
ArrayBuffer response 매개변수로 전달될 때, JSON 문자열은 Encoding 명세 [ENCODING]에
명시된 대로 UTF-8로 인코딩되어야
MUST 한다. 애플리케이션은
TextEncoder 인터페이스
[ENCODING]를 사용하여 JSON 문자열을 인코딩할 수 있다
MAY.
이 절은 비규범적이다.
다음 예제는 하나의 대칭 키를 포함하는 JWK Set이다. (줄바꿈은 읽기 쉽도록 하기 위한 것일 뿐이다.)
{
"keys": [{
"kty": "oct",
"k": "tQ0bJVWb6b0KPL6KtZIy_A",
"kid": "LwVHf8JLtPrv2GUXFW2v_A"
}],
"type": "temporary"
}
이 절은 이벤트의
message 속성을 통해 제공될 라이선스 릴리스 메시지의 형식을 설명한다.
message
이 형식은 JSON 객체이다.
"persistent-license"
타입의 세션에 대해, 객체는 다음 멤버를 포함해야 한다:
MediaKeyMessageEvent 객체의
ArrayBuffer message
속성에 포함될 때, JSON 문자열은 Encoding 명세 [ENCODING]에 명시된 대로 UTF-8로 인코딩된다.
애플리케이션은 TextDecoder 인터페이스
[ENCODING]를 사용하여 ArrayBuffer의 내용을 JSON
문자열로 디코딩할 수 있다 MAY.
이 절은 비규범적이다.
다음 예제는 두 개의 키를 포함했던
"persistent-license"
세션의 라이선스 릴리스이다. (줄바꿈은 읽기 쉽도록 하기 위한 것일 뿐이다.)
{
"kids": [ "LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A" ]
}
이 절은 update() 메서드의
response 매개변수를 통해 제공되는 라이선스 릴리스 확인의 형식을 설명한다.
이 형식은 다음 멤버를 포함하는 JSON 객체이다:
update() 메서드에
ArrayBuffer response 매개변수로 전달될 때, JSON 문자열은 Encoding 명세
[ENCODING]에 명시된 대로 UTF-8로 인코딩되어야
MUST 한다. 애플리케이션은
TextEncoder 인터페이스
[ENCODING]를 사용하여 JSON 문자열을 인코딩할 수 있다
MAY.
이 절은 비규범적이다.
다음 예제는 두 개의 키 ID에 대한 임시 라이선스의 라이선스 요청이다. (줄바꿈은 읽기 쉽도록 하기 위한 것일 뿐이다.)
{
"kids": [
"LwVHf8JLtPrv2GUXFW2v_A",
"0DdtU9od-Bh5L3xbv0Xf_A"
]
}
이 절은 비규범적이다.
base64url 및 그 사용에 대한 자세한 내용은 [RFC7515]의 "Base64url Encoding" 용어 정의와 "Notes on implementing base64url encoding without padding"을 참고한다. 구체적으로 '=' 패딩은 없으며, 문자 '-'와 '_'가 각각 '+'와 '/' 대신 사용되어야 MUST 한다.
사용자 에이전트 및 키 시스템 구현은 MUST
미디어
데이터, 초기화 데이터, update()에 전달되는 데이터,
라이선스, 키 데이터, 그리고 애플리케이션이 제공하는 기타 모든 데이터를 신뢰할 수 없는 콘텐츠 및
잠재적 공격 벡터로 간주해야 한다. 이들은 관련 위협을 완화하기 위해 적절한 보호 조치를 사용해야
MUST 하며, 그러한 데이터를 안전하게 파싱하고 복호화하는 등의 주의를
기울여야 한다. 사용자 에이전트는 데이터를 CDM에 전달하기 전에 검증하는 것이 좋다
SHOULD.
그러한 검증은 CDM이 예를 들어 DOM과 같은 (샌드박스화된) 컨텍스트에서 실행되지 않는 경우 특히 중요하다.
구현은 프로그램 제어 흐름에 영향을 주는 능동 콘텐츠 또는 수동 콘텐츠를 애플리케이션에 반환해서는 안 된다 MUST NOT.
예를 들어, generateRequest()에
전달되는 초기화 데이터의 경우처럼,
미디어 데이터에서 온 것일 수 있는 URL이나 기타 정보를 노출하는 것은 안전하지 않다.
애플리케이션은 사용할 URL을 결정해야 한다.
messageType 속성은
해당되는 경우 애플리케이션이 URL 집합 중에서 선택하는 데 사용할 수 있다.
이벤트의 속성이다.
message
사용자 에이전트는 사용자에게 웹을 안전하게 탐색할 수 있는 방법을 제공할 책임이 있다. 이 책임은 제3자의 기능을 포함하여 사용자 에이전트가 사용하는 모든 기능에 적용된다. 사용자 에이전트 구현자는 키 시스템 구현자로부터 충분한 정보를 얻어 키 시스템과의 통합이 갖는 보안 영향을 적절히 평가할 수 있도록 해야 MUST 한다. 사용자 에이전트 구현자는 CDM 구현이 사용자 에이전트가 사용자에게 보안을 제공하는 데 충분한 제어를 제공하거나 및/또는 지원하도록 보장해야 MUST 한다. 사용자 에이전트 구현자는 CDM 구현이 보안 취약점이 발생한 경우 신속하고 사전 예방적으로 업데이트될 수 있고 그렇게 되도록 보장해야 MUST 한다.
완전히 샌드박스화되지 않았거나 및/또는 플랫폼 기능을 사용하는 CDM 구현을 악용하면, 공격자가 OS 또는 플랫폼 기능에 접근하거나 권한을 상승시키거나(예: system 또는 root로 실행), 드라이버, 커널, 펌웨어, 하드웨어 등에 접근할 수 있다. 그러한 기능, 소프트웨어, 하드웨어는 적대적 소프트웨어나 웹 기반 공격에 견고하도록 작성되지 않았을 수 있으며, 특히 사용자 에이전트와 비교할 때 보안 수정으로 업데이트되지 않을 수 있다. CDM 구현의 보안 취약점 수정 업데이트가 없거나, 드물거나, 느리면 위험이 증가한다. 그러한 CDM 구현과 이를 노출하는 UA는 모든 데이터의 구문 분석을 포함하여 보안의 모든 영역에서 특히 주의해야 MUST 한다.
사용자 에이전트는 클라이언트 OS, 플랫폼 및/또는 하드웨어의 일부이거나 그것들이 제공하는 CDM 또는 기반 메커니즘을 사용할 때 특히 주의를 기울여야 한다.
사용자 에이전트가 충분히 샌드박스화하거나 다른 방식으로 보안할 수 없는 키 시스템 구현을 지원하기로 선택한 경우, 사용자 에이전트는 이를 로드하거나 호출하기 전에 사용자가 충분히 정보를 제공받고 및/또는 명시적으로 동의하도록 보장하는 것이 SHOULD 된다.
인증되지 않은 출처에 권한을 부여하는 것은 네트워크 공격자가 있는 상황에서 임의의 출처에 권한을 부여하는 것과 같다. 지속된 동의의 남용을 보라.
이 절은 비규범적이다.
잠재적 네트워크 공격과 그 영향은 다음을 포함한다:
DNS 스푸핑 공격: 특정 도메인(출처)에 속한다고 주장하는 호스트가 실제로 그 도메인에서 왔다고 보장할 수 없다.
수동 네트워크 공격: 클라이언트와 서버 사이에서 전송되는 데이터, 예를 들어 구별 식별자와 구별 영구 식별자를 포함한 데이터가 다른 엔터티에 의해 보이지 않는다고 보장할 수 없다. 사용자 추적을 참고한다.
능동 네트워크 공격: 추가 스크립트나 iframe이 페이지에 삽입되지 않는다고 보장할 수 없다(이 명세에 정의된 API를 정당한 목적으로 사용하는 페이지와 그렇지 않은 페이지 모두). 그 결과는 다음과 같다:
이 명세에 정의된 API 호출이 임의의 페이지에 삽입될 수 있다.
정당한 이유로 이 API를 사용하는 페이지에서 이 명세에 정의된 API 호출이, 요청된 기능을 수정하거나, 호출을 수정 또는 추가하거나, 데이터를 수정 또는 삽입하는 것을 포함하여 조작될 수 있다. 입력 데이터 공격 및 취약점도 참고한다
클라이언트와 서버 사이에서 전송되는 데이터, 예를 들어 구별 식별자와 구별 영구 식별자를 포함한 데이터가 다른 엔터티에 의해 보이거나 수정될 수 있다. 사용자 추적을 참고한다.
영속 동의의 남용: 이 명세에 정의된 API 사용을 요청하는 호스트가 사용자가 이전에 동의한 호스트라고 보장할 수 없다. 그 결과 인증되지 않은 출처에 권한을 부여하는 것은 네트워크 공격자가 있는 상황에서 모든 출처에 권한을 부여하는 것과 같다.
다음 기법은 위험을 완화할 수 있다:
TLS를 사용하는 애플리케이션은 사용자, 사용자를 대신해 동작하는 소프트웨어, 그리고 같은 도메인에서 왔음을 식별하는 인증서를 가진 TLS 사용 다른 페이지만이 해당 애플리케이션과 상호작용할 수 있음을 확신할 수 있다. 더 나아가, 보안 출처와 결합된 출처별 권한은 애플리케이션에 부여된 권한이 네트워크 공격자에 의해 남용될 수 없도록 보장한다.
이 명세에 정의된 API는 보안 컨텍스트에서만 노출된다. 보안 출처 및 전송도 참고한다.
사용자 에이전트는 안전하지 않은 콘텐츠에 노출될 가능성을 피하기 위해 "차단 가능 콘텐츠" [MIXED-CONTENT]를 차단하는 것을 포함하여, 혼합 콘텐츠 [MIXED-CONTENT]를 적절히 처리해야 MUST 한다. 그러한 노출은 TLS 사용과 같은 다른 완화책을 손상시킬 수 있다.
사용자 에이전트는 신뢰할 수 없는 미디어 데이터가 CDM에 전달되는 것을 방지하여 보안을 더 강화하기 위해 "선택적으로 차단 가능한 콘텐츠" [MIXED-CONTENT]를 포함한 모든 혼합 콘텐츠를 차단하도록 선택할 수 있다 MAY (CDM 공격 및 취약점 참고).
사용자 에이전트는 다른 사용자 에이전트 기능(예: DOM 콘텐츠)보다 더 큰 보안 우려를 제시하는 키 시스템이 출처에 의해 접근될 수 있기 전에, 사용자가 충분히 알도록 하고/하거나 명시적 동의를 제공하도록 보장하는 것이 좋다 SHOULD.
그러한 메커니즘은 유효한 사용이 이후의 악성 접근을 가능하게 하지 않도록 출처별이어야 MUST 하며, 브라우징 프로필별이어야 MUST 한다.
이 절은 비규범적이다.
악성 페이지는 공격을 숨기거나, 사용이 정당한 콘텐츠 제공자로부터 온 것처럼 보이게 하는 등
사용자에게 출처를 속이려는 시도로, 정당한 애플리케이션을 iframe 안에 호스팅할 수 있다.
이는 보안 및/또는 개인정보 보호 이유로
사용자에게 알리거나 동의를 요구하는 구현에 특히 관련된다.
네트워크 공격에 더해, 공격자는 이 명세에 정의된 API의 정당한
사용을 iframe 안에 호스팅함으로써 악용하려고 시도할 수 있다. 정당한
애플리케이션이 작업을 수행하게 함으로써, 공격자는 기존에 부여된 권한(또는 허용 목록)을
재사용하고/하거나 정당한 요청 또는 사용처럼 보일 수 있다.
보안 및/또는 개인정보 보호 이유를 포함하여 사용자에게 알리거나 동의를 요구하는 사용자 에이전트는, 동의의 UI와 영속성을 최상위 Document의 출처와 이 명세에 정의된 API를 사용하는 출처의 조합에 기반하게 하는 것이 좋다 SHOULD. 이는 사용자가 요청을 하는 주 문서를 알 수 있도록 하고, 하나의 (정당한) 조합에 대한 권한 영속화가 악성 사용을 부주의하게 탐지되지 않도록 허용하지 않도록 보장한다.
작성자는 다른 엔터티가 자신의 애플리케이션을 iframe 안에 호스팅하지 못하도록
방지하는 것이 좋다 SHOULD. 정당한 애플리케이션 설계 이유로
호스팅 지원이 필요한 애플리케이션은, 호스팅 문서가 이 명세에 정의된 API를 통해서든
미디어 데이터로서든 CDM에 전달될 어떠한 데이터도 제공하지
못하게 하는 것이 좋으며 SHOULD NOT, 호스팅 프레임이 이 명세에
정의된 API를 호출하지 못하게 하는 것이 좋다 SHOULD NOT.
이 절은 비규범적이다.
예를 들어 geocities.com에서 콘텐츠를 호스팅하는 사용자처럼 하나의 호스트 이름을
공유하는 서로 다른 작성자는 모두 하나의 출처를 공유한다.
사용자 에이전트는 경로명으로 API 접근을 제한하는 기능을 제공하지 않는다.
공유 호스트에서 이 명세에 정의된 API를 사용하면 사용자 에이전트가 구현한 출처 기반 보안 및 개인정보 보호 완화책이 손상된다. 예를 들어, 출처별 구별 식별자는 하나의 호스트 이름에 있는 모든 작성자가 공유하며, 영속 데이터는 그 호스트의 어떤 작성자에 의해서든 접근되고 조작될 수 있다. 후자는 예를 들어 그러한 데이터의 수정 또는 삭제가 특정 콘텐츠에 대한 사용자의 권리를 지울 수 있는 경우 특히 중요하다.
경로 제한 기능이 사용자 에이전트에 의해 제공되더라도, 일반적인 DOM 스크립팅 보안 모델은 이 보호를 우회하고 임의의 경로에서 데이터에 접근하는 것을 사소하게 만들 것이다.
따라서 공유 호스트의 작성자는 이 명세에 정의된 API 사용을 피하는 것이 권장된다 RECOMMENDED. 그렇게 하면 사용자 에이전트의 출처 기반 보안 및 개인정보 보호 완화책이 손상되기 때문이다.
사용자의 기기에 키 시스템이 존재하거나 사용되는 것은 여러 개인정보 보호 문제를 일으키며, 이는 두 범주로 나뉜다: (a) EME 인터페이스 자체 또는 키 시스템 메시지 안에서 공개될 수 있는 사용자별 정보, 그리고 (b) 사용자의 기기에 영속적으로 저장될 수 있는 사용자별 정보.
사용자 에이전트는 사용자가 자신의 개인정보 보호를 적절히 제어할 수 있도록 제공할 책임을 져야 MUST 한다. 사용자 에이전트는 서드파티 CDM 구현과 통합될 수 있으므로, CDM 구현자는 아래에 설명된 기법을 포함하되 이에 국한되지 않는 적절한 기법을 사용자 에이전트 구현자가 구현하여 사용자가 개인정보 보호를 제어할 수 있도록, 충분한 정보와 제어를 제공해야 MUST 한다.
EME 및 키 시스템에 의해 공개되는 정보에 관한 우려는 두 범주로 나뉜다: (a) 특정적이지는 않지만 사용자 에이전트 또는 기기의 핑거프린팅 가능성에 기여할 수 있는 정보에 대한 우려, 그리고 (b) 사용자 추적에 직접 사용될 수 있는 사용자별 정보.
악성 애플리케이션은 지원되는 키 시스템 목록과 관련 정보를 감지하거나 열거함으로써 사용자나 사용자 에이전트를 핑거프린팅할 수 있을 수 있다. 적절한 출처 보호가 제공되지 않으면, 여기에는 방문한 사이트와 해당 사이트에 저장된 정보의 감지가 포함될 수 있다. 특히 키 시스템은 출처 간에 키 또는 기타 데이터를 공유해서는 안 된다 MUST.
이 명세의 여러 기능은 핑거프린팅에 약간 기여할 수 있는 기능 정보를 노출한다:
MediaKeySystemMediaCapability의
encryptionScheme
멤버는 키 시스템이 어떤 암호화 스킴을
지원하는지 드러낸다. 이 정보는 대체로 키 시스템
자체에 의해 결정되므로, 애플리케이션의 키 시스템
선택이 이미 암시하는 것을 넘어서는 정보는 거의 추가하지 않는다.
getStatusForPolicy()는
지정된 HDCP 정책을 강제할 수 있는지 여부를 드러낸다. 이는 현재 연결된 디스플레이 체인의
기능을 반영하며, 사용자가 디스플레이를 재구성하면 세션 중에 변경될 수 있다.
이 절은 비규범적이다.
CDM, 특히 사용자 에이전트 밖에서 구현된 CDM은 웹 플랫폼과 같은 기본 격리를 갖지 않을 수 있다. 정보 유출, 특히 출처 간 정보 유출을 피하기 위한 조치를 취하는 것이 중요하다. 여기에는 메모리 내 데이터와 저장된 데이터가 모두 포함된다. 이를 수행하지 않으면 비공개 브라우징 세션으로부터/세션으로, 브라우징 프로필 간(운영 체제 사용자 계정 간 포함), 심지어 서로 다른 브라우저나 애플리케이션 간에도 정보 유출이 발생할 수 있다.
그러한 문제를 피하기 위해, 사용자 에이전트와 CDM 구현은 다음을 보장해야 MUST 한다.
키, 라이선스, 기타 세션 데이터 및 세션의 존재는
그 세션을 생성한 MediaKeys 객체와 연결된
CDM 인스턴스로 제한된다.
세션 데이터는 그 세션을 생성한
MediaKeys 객체와 연결되지 않은
미디어 요소와 공유되지 않는다. 무엇보다도 이는
세션의 키가 mediaKeys 속성이
그 MediaKeys 객체가 아닌
미디어 요소가 로드한 콘텐츠를 복호화하는 데 사용되어서는 MUST 안 됨을 의미한다.
해당되는 경우, 지속된 세션 데이터는 출처별로 저장된다.
요청하는 출처가 저장한 데이터만 로드될 수 있다.
이 명세에 명시적으로 설명되어 있거나 사용자 권한 없이 다른 웹 플랫폼 API를 통해 페이지에서 사용할 수 있는 정보가 아닌 정보는 CDM에서 추출, 파생 또는 추론할 수 없어야 한다. 이는 예를 들어 CDM 메시지 안에서처럼, 클라이언트 장치 외부 또는 애플리케이션에 노출되는 모든 정보에 적용된다.
이 요구사항이 다루는 정보의 유형에는 다음이 포함되지만 이에 한정되지 않는다.
지리 위치를 포함한 위치
고유 식별자 이외의 자격 증명 또는 식별자
OS 계정 이름 및 기타 잠재적 PII
유사한 정보를 포함할 수 있는 로컬 디렉터리 경로.
로컬 네트워크 세부정보(예: 장치의 로컬 IP 주소)
Bluetooth, USB 및 사용자 미디어를 포함하되 이에 한정되지 않는 로컬 장치.
이 명세에 정의된 API와 관련되어 있지 않거나 그 결과로 저장되지 않은 사용자 상태.
이 절은 비규범적이다.
제3자 호스트(또는 광고주처럼 콘텐츠를 여러 사이트에 배포할 수 있는 어떤 엔터티)는 고유 식별자 또는 라이선스, 키, 키 ID, 또는 라이선스 폐기 기록을 포함하여 CDM이 저장하거나 이를 대신해 저장된 지속 데이터를 사용하여 여러 세션에 걸쳐 사용자를 추적할 수 있다(출처와 브라우징 프로필 전반을 포함함). 이를 통해 사용자의 활동이나 관심사에 대한 프로필을 만들 수 있다. 그러한 추적은 웹 플랫폼의 나머지 부분이 제공하는 개인정보 보호를 약화시키며, 예를 들어 다른 방식으로는 불가능한 고도로 표적화된 광고를 가능하게 할 수 있다. 사용자의 실제 신원을 알고 있는 사이트(예를 들어 인증된 자격 증명을 요구하는 콘텐츠 제공자 또는 전자상거래 사이트)와 결합하면, 순수하게 익명적인 웹 사용만 있는 세계보다 억압적인 집단이 개인을 더 높은 정확도로 표적으로 삼을 수 있다.
이 명세의 API 구현을 통해 얻을 수 있는 사용자 또는 클라이언트별 정보에는 다음이 포함된다.
방문한 출처(저장된 데이터 또는 메모리 내 데이터, 권한 등을 통해)
본 콘텐츠(저장된 또는 메모리 내 라이선스, 키, 키 ID, 라이선스 폐기 기록 등을 통해)
이 명세는 그러한 정보가 일반적으로 사용자 에이전트(및 관련 브라우징 프로필 저장소) 외부에, 흔히 CDM에 저장되기 때문에 특별한 우려를 제기한다.
라이선스와 라이선스 폐기 기록의 내용은 키 시스템별이며, 키 ID는 어떤 값이든 포함할 수 있으므로, 이러한 데이터 항목은 사용자를 식별하는 정보를 저장하는 데 악용될 수 있다.
키 시스템은 장치 또는 장치 사용자를 위한 지속 또는 반지속 식별자에 접근하거나 이를 생성할 수 있다. 어떤 경우에는 이러한 식별자가 특정 장치에 안전한 방식으로 바인딩될 수 있다. 이러한 식별자가 키 시스템 메시지에 존재하면, 장치 및/또는 사용자가 추적될 수 있다. 아래 완화 조치가 적용되지 않으면, 여기에는 시간에 따른 사용자/장치 추적과 주어진 장치의 여러 사용자를 연관시키는 것이 모두 포함될 수 있다.
그러한 식별자, 특히 삭제 불가능하거나 출처별이 아니거나 영구적인 식별자는 쿠키 [COOKIES] 또는 URL에 삽입된 세션 식별자 같은 기존 기법보다 추적 영향이 크다는 점에 유의하는 것이 중요하다.
완화되지 않으면, 그러한 추적은 키 시스템의 설계에 따라 세 가지 형태를 취할 수 있다.
모든 경우에, 그러한 식별자는 키 시스템을 완전히 지원하는 사이트 및/또는 서버에서 사용할 수 있을 것으로 예상된다(따라서 키 시스템 메시지를 해석할 수 있음). 이로 인해 그러한 사이트에 의한 추적이 가능해진다.
키 시스템이 노출하는 식별자가 출처별이 아니면, 키 시스템을 완전히 지원하는 두 사이트 및/또는 서버가 공모하여 사용자를 추적할 수 있다.
키 시스템 메시지가 사용자 식별자에서 일관된 방식으로 파생된 정보를 포함하는 경우, 예를 들어 특정 콘텐츠 항목에 대한 초기 키 시스템 메시지의 일부가 시간이 지나도 변하지 않고 사용자 식별자에 의존하는 경우, 이 정보는 어떤 애플리케이션에 의해서도 장치 또는 사용자를 시간에 따라 추적하는 데 사용될 수 있다.
또한 키 시스템이 키 또는 다른 데이터를 저장하고 출처 간에 재사용하도록 허용하면, 두 출처가 공모하여 공통 키에 접근할 수 있는 능력을 기록함으로써 고유 사용자를 추적하는 것이 가능할 수 있다.
마지막으로, 키 시스템에 대한 사용자 제어용 사용자 인터페이스가 HTTP 세션 쿠키 [COOKIES] 또는 지속 저장소의 데이터와 별도로 데이터를 표시하면, 사용자는 사이트 권한을 변경하거나 데이터를 삭제할 때 어느 하나만 수정하고 나머지는 수정하지 않을 가능성이 크다. 그러면 사이트가 여러 기능을 서로의 중복 백업으로 사용할 수 있어, 개인정보를 보호하려는 사용자의 시도를 무력화할 수 있다.
사이트와 다른 제3자가 사용자를 추적할 가능성에 더해, 사용자 에이전트 구현자, CDM 공급업체 또는 장치 공급업체도 이 명세에 정의된 API를 사용하는 방문 사이트와 같은 사용자의 활동이나 관심사에 대한 프로필을 만들 수 있다. 그러한 추적은 웹 플랫폼의 나머지 부분, 특히 출처 격리와 관련된 개인정보 보호를 약화시킨다.
고유 식별자와 같은 식별자는 CDM 공급업체가 운영하거나 제공하는 서버에서, 예를 들어 개별화 프로세스를 통해 얻어질 수 있다. 이 프로세스에는 고유 영구 식별자를 포함한 클라이언트 식별자를 서버에 제공하는 것이 포함될 수 있다. 출처별 식별자를 생성하기 위해, 출처를 나타내는 값도 제공될 수 있다.
그러한 구현에서, CDM 공급업체는 사용자가 방문한 출처 수 또는 새 식별자가 필요한 횟수 같은 사용자의 활동을 추적할 수 있다. 출처 또는 출처와 연관 가능한 값이 식별자 요청에 제공되면, CDM 공급업체는 사용자 또는 장치 사용자가 방문한 사이트를 추적할 수 있다.
다음 절은 사용자 동의 없는 추적의 위험을 완화할 수 있는 기법을 설명한다.
키 시스템 구현은 가능한 한 고유 식별자와 고유 영구 식별자의 사용을 피하는 것이 SHOULD 되며, 구현의 견고성에 의미 있게 기여하는 경우에만 사용해야 한다. 고유 식별자와 영구 식별자의 사용 제한 또는 회피를 보라.
구현은 고유 영구 식별자를 애플리케이션 또는 출처에 노출해서는 MUST NOT 된다.
고유 식별자는 키 시스템 메시지 안에서 타임스탬프 또는 nonce와 함께 암호화되어야 MUST 하며, 그 결과 키 시스템 메시지는 항상 서로 달라야 한다. 이는 키 시스템을 완전히 지원하는 서버를 제외하고는 키 시스템 메시지가 추적에 사용되는 것을 방지한다. 식별자 암호화를 보라.
사용자 에이전트는 고유 식별자와 키 시스템이 저장한 데이터의 존재를 HTTP 세션 쿠키 [COOKIES]와 강하게 연관되도록 사용자에게 표시하는 것이 SHOULD 되며, "모든 데이터 제거"에 이를 포함하고 같은 UI 위치에 표시해야 한다. 이는 사용자가 그러한 식별자를 건전한 의심을 가지고 보도록 장려할 수 있다. 사용자 에이전트는 사용자가 불완전한 데이터 삭제를 피하도록 도와야 SHOULD 한다.
출처 또는 출처와 연관 가능한 값을 개별화 서버 또는 출처와 관련 없는 다른 엔터티에 제공하지 말 것. 구현이 그러한 프로세스를 사용하는 경우 개별화 절의 요구사항과 권장사항을 따른다.
애플리케이션에 노출되는 모든 고유 식별성 값에 대해, 구현은 각 출처 및 브라우징 프로필마다 서로 다른 애플리케이션에 의해 연관 불가능한 값을 사용해야 MUST 한다. 8.4.1 출처별·프로필별 값 사용을 보라.
이는 고유 식별자를 사용하는 구현에 특히 중요하다. 8.5.3 출처별·프로필별 식별자 사용을 보라.
CDM이 사용하는 데이터 중 애플리케이션 또는 라이선스 서버에 보이는 방식으로 메시지나 동작에 영향을 줄 수 있는 모든 데이터는 출처 및 브라우징 프로필별로 분할되어야 MUST 하며, 비공개 브라우징 세션으로 누출되거나 그로부터 누출되어서는 MUST NOT 된다. 여기에는 메모리 내 데이터와 지속 데이터가 모두 포함된다. 구체적으로 그러나 빠짐없이 열거하는 것은 아니며, 세션 데이터, 라이선스, 키 및 출처별 식별자는 출처별 및 브라우징 프로필별로 분할되어야 MUST 한다. 8.3.1 출처별 및 브라우징 프로필별 키 시스템 저장소 사용 및 8.4.1 출처별·프로필별 값 사용을 보라.
사용자 에이전트는 키 시스템이 유지하는 고유 식별자를 포함한 모든 지속 데이터를 사용자가 삭제할 수 있는 기능을 제공해야 MUST 한다. 지속 데이터를 삭제할 수 있도록 허용을 보라.
사용자 에이전트는, 사용자가 구성한 방식일 수도 있는 방식으로, 일정 시간이 지난 후 고유 식별자 및/또는 기타 키 시스템 데이터를 자동으로 삭제할 MAY 수 있다.
예를 들어, 사용자 에이전트는 그러한 데이터를 세션 전용 저장소로 저장하도록 구성되어, 사용자가 이에 접근할 수 있는 모든 브라우징 컨텍스트를 닫으면 데이터를 삭제할 수 있다.
이는 사이트가 사용자를 추적하는 능력을 제한할 수 있다. 그러면 사이트는 사용자가 그 사이트 자체에서 인증하는 경우(예: 구매하거나 서비스에 로그인함) 여러 세션에 걸쳐서만 사용자를 추적할 수 있기 때문이다.
그러나 사용자가 그러한 만료의 의미를 완전히 이해하지 못하면, 이는 사용자의 콘텐츠, 특히 구매하거나 대여한 콘텐츠에 대한 접근을 위험에 빠뜨릴 수도 있다.
사용자 에이전트는 키 시스템 및/또는 기능에 대한 접근을
브라우징 컨텍스트의 최상위 Document의
출처에서
기원한 스크립트로 제한할 MAY 수 있다. 예를 들어, requestMediaKeySystemAccess()는
iframe에서 실행 중인 다른 출처의 페이지에 대해 특정 구성 요청을 거부할 수 있다.
사용자 에이전트는 고유 식별자 또는 고유 영구 식별자를 사용하기 전에 사용자가 충분히 정보를 제공받고 및/또는 명시적으로 동의하도록 보장해야 MUST 한다.
그러한 메커니즘은 유효한 사용이 이후의 악의적 접근을 가능하게 하는 것을 피하기 위해 출처별이어야 MUST 하며, 브라우징 프로필별이어야 MUST 한다.
이 명세에 정의된 API를 보안 컨텍스트로 제한하면 네트워크 공격자가 인증되지 않은 출처에 부여된 권한을 악용할 수 없도록 보장된다. 지속된 동의의 남용을 보라.
사용자 에이전트는 키 시스템이 활성화되는지 및/또는 키 시스템의 고유 식별자 또는 고유 영구 식별자 사용이 활성화되는지에 대한 전역 제어를 사용자에게 제공하는 것이 SHOULD 된다(키 시스템이 지원하는 경우). 사용자 에이전트는 사용자가 불완전한 데이터 삭제를 피하도록 도와야 SHOULD 한다.
사용자 에이전트는 사이트가 각 키 시스템 및/또는 특정 기능을 사용하기 전에 사용자가 그 접근을 명시적으로 승인하도록 요구할 MAY 수 있다. 사용자 에이전트는 사용자가 이 승인을 일시적으로 또는 영구적으로 철회할 수 있게 해야 SHOULD 한다.
사용자 에이전트는 사용자가 출처 및/또는 키 시스템의 차단 목록을 공유할 수 있게 할 MAY 수 있다. 이는 공동체가 함께 행동하여 개인정보를 보호할 수 있게 한다.
이러한 제안은 이 명세에 정의된 API가 사용자 추적에 사소하게 사용되는 것을 방지하지만, 이를 완전히 차단하지는 않는다. 단일 출처 내에서 사이트는 세션 동안 사용자를 계속 추적할 수 있으며, 사이트가 얻은 식별 정보(이름, 신용카드 번호, 주소)와 함께 이 모든 정보를 제3자에게 전달할 수 있다. 제3자가 여러 사이트와 협력하여 그러한 정보를 얻고, 식별자가 출처 및 프로필별로 고유하지 않다면, 여전히 프로필이 생성될 수 있다.
이 절은 비규범적이다.
키 시스템은 사용자의 기기에 정보를 저장할 수 있고, 또는 사용자 에이전트가 키 시스템을 대신하여 정보를 저장할 수 있다. 잠재적으로 이는 같은 기기의 다른 사용자에게 사용자에 관한 정보를 드러낼 수 있으며, 여기에는 특정 키 시스템을 사용한 출처(즉, 방문한 사이트)나 심지어 키 시스템을 사용하여 복호화된 콘텐츠까지 포함될 수 있다.
한 출처가 저장한 정보가 다른 출처에 대한 키 시스템의 동작에 영향을 주면, 한 사이트에서 사용자가 방문한 사이트나 본 콘텐츠가 다른, 잠재적으로 악성인 사이트에 드러날 수 있다.
클라이언트 기기에서 한 브라우징 프로필을 위해 저장된 정보가 다른 브라우징 프로필 또는 브라우저에 대한 키 시스템의 동작에 영향을 주면, 한쪽에서 방문한 사이트나 본 콘텐츠가 다른 브라우징 프로필에 의해 드러나거나 그것과 상관될 수 있으며, 여기에는 서로 다른 운영 체제 사용자 계정이나 브라우저까지 포함될 수 있다.
이러한 우려를 완화하는 요구사항은 8.3 영속 데이터에 정의되어 있다.
이 절은 비규범적이다.
사용자가 고유 식별자와 저장된 데이터를 삭제하거나 및/또는 키 시스템을 비활성화하여 개인정보를 보호하려는 시도는, 그러한 모든 데이터와 기능뿐만 아니라 쿠키 [COOKIES] 및 기타 사이트 데이터가 동시에 삭제되거나 및/또는 비활성화되지 않으면 무력화될 수 있다. 예:
사용자가 쿠키 또는 기타 지속 저장소를 삭제하면서 고유 식별자와 키 시스템이 저장한 데이터를 함께 삭제하지 않으면, 사이트는 여러 기능을 서로의 중복 백업으로 사용하여 그러한 시도를 무력화할 수 있다.
사용자가 고유 식별자를 삭제하면서 지속 세션을 포함하여 키 시스템이 저장한 데이터와 쿠키 및 기타 지속 저장소를 함께 삭제하지 않으면, 사이트는 남아 있는 데이터를 사용하여 이전 식별자와 새 식별자를 연관시킴으로써 그러한 시도를 무력화할 수 있다.
사용자가 키 시스템을, 특히 특정 출처에 대해 비활성화하면서 쿠키 또는 기타 지속 저장소를 함께 삭제하지 않으면, 사이트는 남아 있는 기능을 사용하여 그러한 시도를 무력화할 수 있다.
사용자가 키 시스템을 비활성화한 뒤, 나중에 키 시스템을 다시 활성화하기로 결정하면서 쿠키 또는 기타 지속 저장소, 고유 식별자, 그리고 키 시스템이 저장한 데이터를 함께 삭제하지 않으면, 사이트는 비활성화 이전의 데이터를 키 시스템이 다시 활성화된 이후의 데이터 및 동작과 연관시킬 수 있다.
이러한 우려를 완화하는 권고는 8.3 영속 데이터에 정의되어 있다.
사용자 에이전트는 사용자 익명성을 보존하고/하거나 브라우징 활동 기록이 클라이언트에 영속화되지 않도록 하기 위한 동작 모드(예: 비공개 브라우징)를 지원할 수 있다. 이전 절에서 논의한 개인정보 보호 우려는 그러한 모드를 사용하는 사용자에게 특히 우려될 수 있다.
그러한 모드를 지원하는 사용자 에이전트 구현자는 이러한 모드에서 키 시스템에 대한 접근을 비활성화해야 하는지 신중히
고려하는 것이 좋다 SHOULD. 예를 들어, 그러한 모드는
MediaKeySystemAccess
객체 중
persistentState 또는
distinctiveIdentifier를
지원하거나 사용하는 객체의 생성을 금지할 수 있다 MAY
(이는 CDM 구현의 일부로서일 수도 있고, 애플리케이션이 그것들을
"required"라고 표시했기 때문일
수도 있다). 구현이 그러한 생성을 금지하지 않는다면, 이를 허용하기 전에 그러한 모드의 예상되는
개인정보 보호 속성에 대한 의미와 잠재적 결과를 사용자에게 알리는 것이 좋다
SHOULD.
이 명세에 정의된 API는 보안 출처에서만 지원되며, 이전 절에서 논의한 정보를 보호한다. 식별자는 식별자 암호화에 명시된 대로 추가로 암호화된다.
애플리케이션은, 사용하는 서버를 포함하여, CDM으로부터의 데이터나 메시지를 포함하거나
관련된 모든 트래픽에 보안 전송을 사용하는 것이 좋다 SHOULD. 여기에는
이벤트에서
전달되는 모든 데이터와 messageupdate()에
전달되는 모든 데이터가 포함되지만 이에 국한되지 않는다.
모든 사용자 에이전트는 사용자 에이전트 또는 애플리케이션이 보안 출처와 전송을 강제하려는 경우 안전하지 않은 콘텐츠나 전송에 노출되지 않도록 혼합 콘텐츠 [MIXED-CONTENT]를 적절히 처리해야 MUST 한다.
비규범적으로 표시된 절뿐 아니라, 이 명세의 모든 작성 지침, 다이어그램, 예제 및 참고는 비규범적이다. 이 명세의 그 밖의 모든 것은 규범적이다.
이 문서의 핵심 단어 MAY, MUST, MUST NOT, OPTIONAL, RECOMMENDED, REQUIRED, SHALL, SHALL NOT, SHOULD, 및 SHOULD NOT는 여기에 보인 것처럼 모두 대문자로 나타날 때, 그리고 오직 그때에만, BCP 14 [RFC2119] [RFC8174]에 설명된 대로 해석된다.
이 절은 비규범적이다.
이 절은 제안된 확장을 사용하여 다양한 사용 사례에 대한 예제 해결책을 포함한다. 이것들이 이러한 사용 사례에 대한 유일한 해결책은 아니다. 예제에서는 video 요소를 사용하지만, 모든 미디어 요소에도 동일하게 적용된다. 동기 XHR 사용과 같은 일부 경우에는 확장에 초점을 맞추기 위해 예제를 단순화했다.
이 간단한 예제에서는 소스 파일과 평문 라이선스가 페이지에 하드코딩되어 있다. 세션은 언제나 하나만 생성된다.
<script>
function onLoad() {
var video = document.getElementById('video');
if (!video.mediaKeys) {
navigator.requestMediaKeySystemAccess('org.w3.clearkey', [
{ initDataTypes: ['webm'],
videoCapabilities: [{ contentType: 'video/webm; codecs="vp8"' }] }
]).then(
function(keySystemAccess) {
var promise = keySystemAccess.createMediaKeys();
promise.catch(
console.error.bind(console, 'Unable to create MediaKeys')
);
promise.then(
function(createdMediaKeys) {
return video.setMediaKeys(createdMediaKeys);
}
).catch(
console.error.bind(console, 'Unable to set MediaKeys')
);
promise.then(
function(createdMediaKeys) {
var te = new TextEncoder();
var initData = te.encode( '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"]}');
var keySession = createdMediaKeys.createSession();
keySession.addEventListener("message", handleMessage, false);
return keySession.generateRequest('keyids', initData);
}
).catch(
console.error.bind(console, 'Unable to create or initialize key session')
);
}
);
}
}
function handleMessage(event) {
var keySession = event.target;
var te = new TextEncoder();
var license = te.encode('{"keys":[{"kty":"oct","k":"tQ0bJVWb6b0KPL6KtZIy_A","kid":"LwVHf8JLtPrv2GUXFW2v_A"}],"type":"temporary"}');
keySession.update(license).catch(
console.error.bind(console, 'update() failed')
);
}
</script>
<body onload='onLoad()'>
<video src='foo.webm' autoplay id='video'></video>
</body>
이 예제는 requestMediaKeySystemAccess()
메서드를 사용하여 지원되는 키 시스템을 선택한 다음,
라이선스 요청을 생성하고 적절한 라이선스 서버로 보내기 위해 미디어 데이터의
초기화 데이터를 사용한다.
지원되는 키 시스템 중 하나는 serverCertificate를 사용하며, 이는 사전에 제공된다.
<script>
var licenseUrl;
var serverCertificate;
// Returns a Promise<MediaKeys>.
function createSupportedKeySystem() {
someSystemOptions = [
{ initDataTypes: ['keyids', 'webm'],
audioCapabilities: [
{ contentType: 'audio/webm; codecs="opus"' },
{ contentType: 'audio/webm; codecs="vorbis"' }
],
videoCapabilities: [
{ contentType: 'video/webm; codecs="vp9"' },
{ contentType: 'video/webm; codecs="vp8"' }
]
}
];
clearKeyOptions = [
{ initDataTypes: ['keyids', 'webm'],
audioCapabilities: [
{ contentType: 'audio/webm; codecs="opus"' },
{ contentType: 'audio/webm; codecs="vorbis"' }
],
videoCapabilities: [
{ contentType: 'video/webm; codecs="vp9"',
robustness: 'foo' },
{ contentType: 'video/webm; codecs="vp9"',
robustness: 'bar' },
{ contentType: 'video/webm; codecs="vp8"',
robustness: 'bar' },
]
}
];
return navigator.requestMediaKeySystemAccess('com.example.somesystem', someSystemOptions).then(
function(keySystemAccess) {
// Not shown:
// 1. Use both attributes of keySystemAccess.getConfiguration().audioCapabilities[0]
// and both attributes of keySystemAccess.getConfiguration().videoCapabilities[0]
// to retrieve appropriate stream(s).
// 2. Set video.src.
licenseUrl = 'https://license.example.com/getkey';
serverCertificate = new Uint8Array([ ... ]);
return keySystemAccess.createMediaKeys();
}
).catch(
function(error) {
// Try the next key system.
navigator.requestMediaKeySystemAccess('org.w3.clearkey', clearKeyOptions).then(
function(keySystemAccess) {
// Not shown:
// 1. Use keySystemAccess.getConfiguration().audioCapabilities[0].contentType
// and keySystemAccess.getConfiguration().videoCapabilities[0].contentType
// to retrieve appropriate stream(s).
// 2. Set video.src.
licenseUrl = 'https://license.example.com/clearkey/request';
return keySystemAccess.createMediaKeys();
}
);
}
).catch(
console.error.bind(console, 'Unable to instantiate a key system supporting the required combinations')
);
}
function handleInitData(event) {
var video = event.target;
if (video.mediaKeysObject === undefined) {
video.mediaKeysObject = null; // Prevent entering this path again.
video.pendingSessionData = []; // Will store all initData until the MediaKeys is ready.
createSupportedKeySystem().then(
function(createdMediaKeys) {
video.mediaKeysObject = createdMediaKeys;
if (serverCertificate)
createdMediaKeys.setServerCertificate(serverCertificate);
for (var i = 0; i < video.pendingSessionData.length; i++) {
var data = video.pendingSessionData[i];
makeNewRequest(video.mediaKeysObject, data.initDataType, data.initData);
}
video.pendingSessionData = [];
return video.setMediaKeys(createdMediaKeys);
}
).catch(
console.error.bind(console, 'Failed to create and initialize a MediaKeys object')
);
}
addSession(video, event.initDataType, event.initData);
}
function addSession(video, initDataType, initData) {
if (video.mediaKeysObject) {
makeNewRequest(video.mediaKeysObject, initDataType, initData);
} else {
video.pendingSessionData.push({initDataType: initDataType, initData: initData});
}
}
function makeNewRequest(mediaKeys, initDataType, initData) {
var keySession = mediaKeys.createSession();
keySession.addEventListener("message", licenseRequestReady, false);
keySession.generateRequest(initDataType, initData).catch(
console.error.bind(console, 'Unable to create or initialize key session')
);
}
function licenseRequestReady(event) {
var request = event.message;
var xmlhttp = new XMLHttpRequest();
xmlhttp.keySession = event.target;
xmlhttp.open("POST", licenseUrl);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4) {
var license = new Uint8Array(xmlhttp.response);
xmlhttp.keySession.update(license).catch(
console.error.bind(console, 'update() failed')
);
}
}
xmlhttp.send(request);
}
</script>
<video autoplay onencrypted='handleInitData(event)'></video>
MediaKeys 초기화 중에 encrypted 이벤트를 처리할
필요가 없다면 초기화는 훨씬 단순하다. 이는 초기화 데이터를 다른 방식으로 제공하거나,
MediaKeys 객체가 생성된 후 소스를 설정하여
달성할 수 있다. 이 예제는 후자를 수행한다.
<script>
var licenseUrl;
var serverCertificate;
var mediaKeys;
// See the previous example for implementations of these functions.
function createSupportedKeySystem() { ... }
function makeNewRequest(mediaKeys, initDataType, initData) { ... }
function licenseRequestReady(event) { ... }
function handleInitData(event) {
makeNewRequest(mediaKeys, event.initDataType, event.initData);
}
createSupportedKeySystem().then(
function(createdMediaKeys) {
mediaKeys = createdMediaKeys;
var video = document.getElementById("v");
video.src = 'foo.webm';
if (serverCertificate)
mediaKeys.setServerCertificate(serverCertificate);
return video.setMediaKeys(mediaKeys);
}
).catch(
console.error.bind(console, 'Failed to create and initialize a MediaKeys object')
);
</script>
<video id="v" autoplay onencrypted='handleInitData(event)'></video>
이것은 모든 이벤트가 사용되는 모습을 보여 주는 더 완전한 예제이다.
handleMessage()는 여러 번 호출될 수 있음에 유의한다. 여기에는 여러 번의 왕복이
필요한 경우 update() 호출에 대한
응답으로 호출되는 경우와, 키 시스템이 메시지를 보내야 할 수 있는 기타 모든 이유가 포함된다.
<script>
var licenseUrl;
var serverCertificate;
var mediaKeys;
// See previous examples for implementations of these functions.
// createSupportedKeySystem() additionally sets renewalUrl.
function createSupportedKeySystem() { ... }
function handleInitData(event) { ... }
// This replaces the implementation in the previous example.
function makeNewRequest(mediaKeys, initDataType, initData) {
var keySession = mediaKeys.createSession();
keySession.addEventListener('message', handleMessage, false);
keySession.addEventListener('keystatuseschange', handlekeyStatusesChange, false);
keySession.closed.then(
function(reason) {
console.log('Session', this.sessionId, 'closed, reason', reason);
}.bind(keySession)
);
keySession.generateRequest(initDataType, initData).catch(
console.error.bind(console, 'Unable to create or initialize key session')
);
}
function handleMessageResponse(keySession, response) {
var license = new Uint8Array(response);
keySession.update(license).catch(
function(err) {
console.error('update() failed: ' + err);
}
);
}
function sendMessage(type, message, keySession) {
var url = licenseUrl;
if (type == "license-renewal")
url = renewalUrl;
xmlhttp = new XMLHttpRequest();
xmlhttp.keySession = keySession;
xmlhttp.open('POST', url);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4)
handleMessageResponse(xmlhttp.keySession, xmlhttp.response);
}
xmlhttp.send(message);
}
function handleMessage(event) {
sendMessage(event.messageType, event.message, event.target);
}
function handlekeyStatusesChange(event) {
// Evaluate the current state using one of the map-like methods exposed by
// event.target.keyStatuses.
// For example:
event.target.keyStatuses.forEach(function(status, keyId) {
switch (status) {
case "usable":
break;
case "expired":
// Report an expired key.
break;
case "status-pending":
// The status is not yet known. Consider the key unusable until the status is updated.
break;
default:
// Do something with |keyId| and |status|.
}
})
}
createSupportedKeySystem().then(
function(createdMediaKeys) {
mediaKeys = createdMediaKeys;
var video = document.getElementById("v");
video.src = 'foo.webm';
if (serverCertificate)
mediaKeys.setServerCertificate(serverCertificate);
return video.setMediaKeys(mediaKeys);
}
).catch(
console.error.bind(console, 'Failed to create and initialize a MediaKeys object')
);
</script>
<video id="v" autoplay onencrypted='handleInitData(event)'></video>
이 예제는 나중에 사용하기 위한 영속 라이선스를 요청하고 저장한다. 또한 나중에 라이선스를 가져오는 함수와 이를 파기하는 함수를 제공한다.
<script>
var licenseUrl;
var serverCertificate;
var mediaKeys;
// See the previous examples for implementations of these functions.
// createSupportedKeySystem() additionally sets persistentState: "required" in each options dictionary.
function createSupportedKeySystem() { ... }
function sendMessage(message, keySession) { ... }
function handleMessage(event) { ... }
// Called if the application does not have a stored sessionId for the media resource.
function makeNewRequest(mediaKeys, initDataType, initData) {
var keySession = mediaKeys.createSession("persistent-license");
keySession.addEventListener('message', handleMessage, false);
keySession.closed.then(
function(reason) {
console.log('Session', this.sessionId, 'closed, reason', reason);
}.bind(keySession)
);
keySession.generateRequest(initDataType, initData).then(
function() {
// Store this.sessionId in the application.
}.bind(keySession)
).catch(
console.error.bind(console, 'Unable to request a persistent license')
);
}
// Called if the application has a stored sessionId for the media resource.
function loadStoredSession(mediaKeys, sessionId) {
var keySession = mediaKeys.createSession("persistent-license");
keySession.addEventListener('message', handleMessage, false);
keySession.closed.then(
function(reason) {
console.log('Session', this.sessionId, 'closed, reason', reason);
}.bind(keySession)
);
keySession.load(sessionId).then(
function(loaded) {
if (!loaded) {
console.error('No stored session with the ID ' + sessionId + ' was found.');
// The application should remove its record of |sessionId|.
return;
}
}
).catch(
console.error.bind(console, 'Unable to load or initialize the stored session with the ID ' + sessionId)
);
}
// Called when the application wants to stop using the session without removing the stored license.
function closeSession(keySession) {
keySession.close();
}
// Called when the application wants to remove the stored license.
// The stored session data has not been completely removed until the promise returned by remove() is fulfilled.
// The remove() call may initiate a series of messages to/from the server that must be completed before this occurs.
function removeStoredSession(keySession) {
keySession.remove().then(
function() {
console.log('Session ' + this.sessionId + ' removed');
// The application should remove its record of this.sessionId.
}.bind(keySession)
).catch(
console.error.bind(console, 'Failed to remove the session')
);
}
// This replaces the implementation in the previous example.
function handleMessageResponse(keySession, response) {
var license = new Uint8Array(response);
keySession.update(license).then(
function() {
// If this was the last required message from the server, the license is
// now stored. Update the application state as appropriate.
}
).catch(
console.error.bind(console, 'update() failed')
);
}
createSupportedKeySystem().then(
function(createdMediaKeys) {
mediaKeys = createdMediaKeys;
var video = document.getElementById("v");
if (serverCertificate)
mediaKeys.setServerCertificate(serverCertificate);
return video.setMediaKeys(mediaKeys);
}
).catch(
console.error.bind(console, 'Failed to create and initialize a MediaKeys object')
);
</script>
<video id='v' src='foo.webm' autoplay></video>
일부 미디어가 라이선스 안에 HDCP 정책을 갖게 될 경우, 애플리케이션은 사전 가져오기 전에 해당 버전을 확인할 수 있다.
const status = await video.mediaKeys.getStatusForPolicy({
minHdcpVersion: '1.4'
});
if (status === 'usable') {
// Pre-fetch HD content.
} else { // 'output-restricted'
// Pre-fetch SD content.
}
편집자들은 이 명세에 기여해 준 Aaron Colwell, Alex Russell, Anne van Kesteren, Bob Lund, Boris Zbarsky, Chris Needham, Chris Pearce, David Singer, Domenic Denicola, Frank Galligan, Glenn Adams, Henri Sivonen, Jer Noble, Joe Steele, Joey Parrish, John Simmons, Mark Vickers, Pavel Pergamenshchik, Philip Jägenstedt, Pierre Lemieux, Robert O'Callahan, Ryan Sleevi, Steve Heffernan, Steven Robertson Theresa O'Connor, Thomás Inskip, Travis Leithead, 그리고 Xiaohan Wang에게 감사한다. 메일링 리스트와 이슈 참여를 포함하여 명세에 기여해 준 많은 다른 분들께도 감사드린다.
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: