1. 소개
이 섹션은 비규범적입니다.
이 표준은 HTML 문서와 서비스 워커에서 실행되는 스크립트를 위한 비동기 쿠키 API를 정의합니다.
HTTP 쿠키는 넷스케이프에서 시작된 이래 (archive.org에서 보존된 문서)와 같이, 웹을 위한 유용한 상태 관리 메커니즘을 제공해 왔습니다.
쿠키에 대한 동기적 단일 스레드 스크립트 수준 document.cookie
인터페이스는 복잡성 및 성능
문제의 원인이었으며, 많은 브라우저가 다음과 같이 변화함에 따라 더 악화되었습니다:
-
단일 브라우저 프로세스,
-
단일 스레드 이벤트 루프 모델, 그리고
-
쿠키 작업 처리 중 스크립트 이벤트 핸들링의 일반적인 반응성 기대 없음
…에서, 현대 웹은 부드럽고 반응성이 뛰어난 고성능을 지향합니다:
-
다중 브라우저 프로세스에서,
-
멀티스레드, 다중 이벤트 루프 모델로, 그리고
-
인간 반사 신경 수준의 시간 내 반응성을 기대합니다.
현대 웹에서는 웹 애플리케이션의 한 부분에서 쿠키 작업이 다음을 차단할 수 없습니다:
-
웹 애플리케이션의 나머지 부분,
-
웹 오리진의 나머지 부분, 또는
-
브라우저 전체.
서비스 워커에서 구축된 웹의 새로운 부분도 쿠키에 접근할 필요가 있지만, 동기적이고
블로킹되는 document.cookie
인터페이스는 문서가 없고 이벤트 루프를 차단할 수 없으므로 사용할 수 없습니다. 이벤트 루프를 차단하면 관련 없는 이벤트 처리에 영향을 주기 때문입니다.
1.1. document.cookie
의 대안
오늘날 쿠키를 작성하려면 브라우저가 Set-Cookie
형식으로 정교하게 작성된 쿠키 문자열로 쿠키 저장소를 동기적으로 업데이트할 때까지 이벤트 루프를 차단해야 합니다:
document. cookie= '__Secure-COOKIENAME=cookie-value' + '; Path=/' + '; expires=Fri, 12 Aug 2016 23:05:17 GMT' + '; Secure' + '; Domain=example.org' ; // 이제 쓰기가 성공했다고 가정할 수 있지만, 실패는 조용히 발생하므로 알기 어렵다. // 그래서 쓰기가 성공했는지 확인하기 위해 읽는다. var successRegExp= /(^|; ?)__Secure-COOKIENAME=cookie-value(;|$)/ ; if ( String( document. cookie). match( successRegExp)) { console. log( '성공!' ); } else { console. error( '실패하였으며, 이유를 알 수 없습니다.' ); }
대신 이렇게 쓸 수 있다면 어떨까요?
const one_day_ms= 24 * 60 * 60 * 1000 ; cookieStore. set( { name: '__Secure-COOKIENAME' , value: 'cookie-value' , expires: Date. now() + one_day_ms, domain: 'example.org' }). then( function () { console. log( '성공!' ); }, function ( reason) { console. error( '실패하였으며, 이유는 다음과 같습니다:' , reason); }); // 쿠키 저장소가 쓰기를 처리하는 동안 다른 작업을 할 수 있습니다.
이 방식은 문서에 의존하지 않고 블로킹하지 않으므로 서비스 워커에서도 사용할 수 있습니다. 서비스 워커는 스크립트에서 쿠키에 접근할 수 없기 때문입니다.
이 표준에는 setTimeout
기반 폴링 쿠키 모니터를 쿠키 변경 옵저버로 대체하는 에너지 효율적인 모니터링 API도 포함되어 있습니다.
1.2. 요약
요약하면, 이 API는 다음 기능을 제공합니다:
-
쿠키 작성(또는 "설정") 및 삭제(또는 "만료")
-
읽기(또는 "가져오기") 스크립트에서 볼 수 있는 쿠키
-
... 서비스 워커 컨텍스트 내 지정된 요청 경로에 대해서도 포함
-
-
모니터링 스크립트에서 볼 수 있는 쿠키 변경사항
CookieChangeEvent
로 감지-
... 장시간 실행되는 스크립트 컨텍스트(예:
document
)에서 -
... 서비스 워커 컨텍스트 내 스크립트 제공 요청 경로에 대해
-
1.3. 쿠키 조회
문서와 서비스
워커 모두 동일한 조회 API에 접근합니다.
cookieStore
속성을 글로벌 객체에서 사용합니다.
get()
및 getAll()
메서드는 CookieStore
에서 쿠키를 조회하는 데 사용됩니다.
두 메서드 모두 Promise
를
반환합니다.
두 메서드는 같은 인자를 받을 수 있으며, 인자는 다음 중 하나입니다:
-
이름, 또는
-
옵션 딕셔너리(
getAll()
에서는 선택사항)
get()
메서드는 사실상 getAll()
의 첫 번째 결과만 반환하는 형태입니다.
try { const cookie= await cookieStore. get( 'session_id' ); if ( cookie) { console. log( ` ${ cookie. name} 쿠키 발견: ${ cookie. value} ` ); } else { console. log( '쿠키를 찾을 수 없음' ); } } catch ( e) { console. error( `쿠키 저장소 오류: ${ e} ` ); }
try { const cookies= await cookieStore. getAll( 'session_id' }); for ( const cookieof cookies) console. log( `결과: ${ cookie. name} = ${ cookie. value} ` ); } catch ( e) { console. error( `쿠키 저장소 오류: ${ e} ` ); }
서비스 워커는 자신의 fetch에서 scope 하의 모든 URL에 대해 전송될 쿠키 목록을 얻을 수 있습니다.
문서는 현재 URL의 쿠키만 얻을 수 있습니다. 즉, url 값으로 허용되는 것은 문서 컨텍스트에서는 문서의 URL뿐입니다.
get()
및 getAll()
이 반환하는 객체에는 쿠키 저장소의 모든 관련 정보가 담겨 있습니다. 이전 document.cookie
API처럼 이름과 값만이 아니라 전체 정보를 얻을 수 있습니다.
await cookie= cookieStore. get( 'session_id' ); console. log( `쿠키 범위 - Domain: ${ cookie. domain} Path: ${ cookie. path} ` ); if ( cookie. expires=== null ) { console. log( '쿠키는 세션 종료 시 만료됩니다.' ); } else { console. log( `쿠키 만료 시각: ${ cookie. expires} ` ); } if ( cookie. secure) console. log( '쿠키는 보안 오리진에만 제한됩니다.' );
1.4. 쿠키 수정
문서와 서비스
워커 모두 동일한 수정 API에 접근합니다.
cookieStore
속성을 글로벌 객체에서 사용합니다.
쿠키를 생성하거나 수정(쓰기)할 때 set()
메서드를 사용합니다.
try { await cookieStore. set( 'opted_out' , '1' ); } catch ( e) { console. error( `쿠키 설정 실패: ${ e} ` ); }
위의 set()
호출은 옵션 딕셔너리를 사용하는 단축 형태입니다. 예시:
await cookieStore. set({ name: 'opted_out' , value: '1' , expires: null , // 세션 쿠키 // 기본적으로 domain은 null로 현재 도메인에만 범위가 한정된다. domain: null , path: '/' });
쿠키를 삭제(만료)할 때는 delete()
메서드를 사용합니다.
try { await cookieStore. delete ( 'session_id' ); } catch ( e) { console. error( `쿠키 삭제 실패: ${ e} ` ); }
내부적으로, 쿠키 삭제는 쿠키의 만료 날짜를 과거로 변경하는 방식으로 처리됩니다. 이 방식은 여전히 작동합니다.
try { const one_day_ms= 24 * 60 * 60 * 1000 ; await cookieStore. set({ name: 'session_id' , value: 'value will be ignored' , expires: Date. now() - one_day_ms}); } catch ( e) { console. error( `쿠키 삭제 실패: ${ e} ` ); }
1.5. 쿠키 모니터링
폴링을 피하기 위해 쿠키 변경을 관찰할 수 있습니다.
문서에서는 모든 관련 쿠키 변경에 대해 change
이벤트가 발생합니다.
change
이벤트 등록:
cookieStore. addEventListener( 'change' , event=> { console. log( ` ${ event. changed. length} 개의 쿠키가 변경됨` ); for ( const cookiein event. changed) console. log( `쿠키 ${ cookie. name} 가 ${ cookie. value} 로 변경됨` ); console. log( ` ${ event. deleted. length} 개의 쿠키가 삭제됨` ); for ( const cookiein event. deleted) console. log( `쿠키 ${ cookie. name} 가 삭제됨` ); });
서비스 워커에서는 cookiechange
이벤트가 글로벌 스코프에 대해 발생하지만, 서비스 워커
등록과 연계된 명시적 구독이 필요합니다.
cookiechange
이벤트 등록:
self. addEventListener( 'activate' , ( event) => { event. waitUntil( async () => { // 현재 구독 상태 스냅샷 const subscriptions= await self. registration. cookies. getSubscriptions(); // 기존 구독 모두 해제 await self. registration. cookies. unsubscribe( subscriptions); await self. registration. cookies. subscribe([ { name: 'session_id' , // session_id 이름의 쿠키 변경 이벤트 수신 } ]); }); }); self. addEventListener( 'cookiechange' , event=> { // event에는 Document 이벤트와 동일한 의미의 |changed|, |deleted| 속성이 있음 console. log( ` ${ event. changed. length} 개의 쿠키가 변경됨` ); console. log( ` ${ event. deleted. length} 개의 쿠키가 삭제됨` ); });
subscribe()
호출은 누적적입니다. 따라서 독립적으로 관리되는 모듈이나 라이브러리도 자체적으로 구독을 설정할 수 있습니다. 예상대로, 서비스
워커의
구독은 서비스 워커 등록과 함께 지속적으로 유지됩니다.
구독은 get()
및 getAll()
과 동일한 옵션을 사용할 수 있습니다.
세밀한 구독의 복잡성은 서비스 워커에
불필요한 쿠키 변경 이벤트를 디스패치하는 비용이, Window
에 디스패치하는 것보다 훨씬 높기 때문입니다.
특히 서비스 워커에 이벤트를 디스패치하면
워커를 깨워야 할 수도 있는데, 이는 배터리 수명에 큰 영향을 미칩니다.
getSubscriptions()
는 서비스 워커가 현재 구독 정보를 조회할 수 있게 해줍니다.
const subscriptions= await self. registration. cookies. getSubscriptions(); for ( const subof subscriptions) { console. log( sub. name, sub. url); }
2. 개념
2.1. 쿠키
쿠키는 사용자 에이전트에 대해 Cookies § 사용자 에이전트 요구사항에서 규범적으로 정의됩니다.
쿠키 이름이나 값을 정규화한다는 것은 string input이 주어졌을 때, input의 시작이나 끝에 있는 모든 U+0009 TAB 및 U+0020 SPACE를 제거하는 것이다.
쿠키는 스크립트에서 볼 수 있음 상태일 때, 범위 내에 있고 http-only-flag가 비활성화된 경우입니다. 이는 처리 모델에서 더 형식적으로 강제되며, 적절한 시점에 Cookies § 조회 모델을 참조합니다.
쿠키는 또한 특정 크기 제한을 받습니다. Cookies § 저장 모델에 따르면:
-
name과 value 필드의 합산 길이는 4096 바이트를 초과할 수 없습니다 (최대 name/value 쌍 크기).
-
name과 value를 제외한 각 필드의 길이는 1024 바이트를 초과할 수 없습니다 (최대 속성 값 크기).
쿠키 속성 값은 바이트 시퀀스로 저장되며, 문자열이 아닙니다.
2.2. 쿠키 저장소
쿠키 저장소는 사용자 에이전트에 대해 Cookies § 사용자 에이전트 요구사항에서 규범적으로 정의됩니다.
쿠키 저장소에 대해 다음 조건 중 하나가 발생하면 쿠키 변경 처리 단계를 수행합니다.
2.3. 서비스 워커 확장
[Service-Workers] 에서는 서비스 워커 등록을 정의하며, 이 명세서가 이를 확장합니다.
서비스 워커 등록에는 쿠키 변경 구독 목록이 연관되어 있으며, 이는 리스트입니다; 각 원소는 쿠키 변경 구독입니다. 쿠키 변경 구독은 튜플이며, name과 url로 구성됩니다.
3. CookieStore
인터페이스
[Exposed =(ServiceWorker ,Window ),SecureContext ]interface :
CookieStore EventTarget {Promise <CookieListItem ?>get (USVString );
name Promise <CookieListItem ?>get (optional CookieStoreGetOptions = {});
options Promise <CookieList >getAll (USVString );
name Promise <CookieList >getAll (optional CookieStoreGetOptions = {});
options Promise <undefined >set (USVString ,
name USVString );
value Promise <undefined >set (CookieInit );
options Promise <undefined >delete (USVString );
name Promise <undefined >delete (CookieStoreDeleteOptions ); [
options Exposed =Window ]attribute EventHandler ; };
onchange dictionary {
CookieStoreGetOptions USVString ;
name USVString ; };
url enum {
CookieSameSite ,
"strict" ,
"lax" };
"none" dictionary {
CookieInit required USVString ;
name required USVString ;
value DOMHighResTimeStamp ?=
expires null ;USVString ?=
domain null ;USVString = "/";
path CookieSameSite = "strict";
sameSite boolean =
partitioned false ; };dictionary {
CookieStoreDeleteOptions required USVString ;
name USVString ?=
domain null ;USVString = "/";
path boolean =
partitioned false ; };dictionary {
CookieListItem USVString ;
name USVString ; };
value typedef sequence <CookieListItem >;
CookieList
3.1. get()
메서드
- cookie = await cookieStore .
get
(name)- cookie = await cookieStore .
get
(options) - cookie = await cookieStore .
-
주어진 쿠키 이름(또는 기타 옵션)에 대해 범위 내에 있는 첫 번째 스크립트에서 볼 수 있는 값을 반환하는 promise를 리턴합니다. 서비스 워커 컨텍스트에서는 기본적으로 서비스 워커의 등록된 scope 경로가 사용됩니다. 문서에서는 현재 문서의 경로가 기본값이며,
replaceState()
또는document.domain
의 변경을 반영하지 않습니다.
get(name)
메서드 단계:
-
origin을 settings의 origin으로 설정합니다.
-
origin이 opaque origin이라면, "
SecurityError
"DOMException
으로 거부된 promise를 반환합니다. -
url을 settings의 생성 URL로 설정합니다.
-
p를 새 promise로 설정합니다.
-
다음 단계들을 병렬로 실행합니다:
-
p를 반환합니다.
get(options)
메서드 단계:
-
origin을 settings의 origin으로 설정합니다.
-
origin이 opaque origin이라면, "
SecurityError
"DOMException
으로 거부된 promise를 반환합니다. -
url을 settings의 생성 URL로 설정합니다.
-
options가 비어 있다면
TypeError
로 거부된 promise를 반환합니다. -
options["
url
"] 이 존재한다면, 다음 단계를 실행합니다:-
parsed를 파싱 options["
url
"] 및 settings의 API base URL로 설정합니다. -
this의 관련 글로벌 객체가
Window
이고, parsed가 url과 exclude fragments true로 같지 않으면,TypeError
로 거부된 promise를 반환합니다. -
parsed의 origin과 url의 origin이 동일 출처가 아니면,
TypeError
로 거부된 promise를 반환합니다. -
url을 parsed로 설정합니다.
-
-
p를 새 promise로 설정합니다.
-
다음 단계들을 병렬로 실행합니다:
-
p를 반환합니다.
3.2. getAll()
메서드
- cookies = await cookieStore .
getAll
(name)- cookies = await cookieStore .
getAll
(options) - cookies = await cookieStore .
-
주어진 쿠키 이름(또는 기타 옵션)에 대해 범위 내에 있는 모든 스크립트에서 볼 수 있는 값을 반환하는 promise를 리턴합니다. 서비스 워커 컨텍스트에서는 기본적으로 서비스 워커의 등록된 scope 경로가 사용됩니다. 문서에서는 현재 문서의 경로가 기본값이며,
replaceState()
또는document.domain
의 변경을 반영하지 않습니다.
getAll(name)
메서드 단계:
-
origin을 settings의 origin으로 설정합니다.
-
origin이 opaque origin이라면, "
SecurityError
"DOMException
으로 거부된 promise를 반환합니다. -
url을 settings의 생성 URL로 설정합니다.
-
p를 새 promise로 설정합니다.
-
다음 단계들을 병렬로 실행합니다:
-
list를 query cookies를 url과 name을 인자로 실행한 결과로 설정합니다.
-
그 외에는, list로 p를 resolve합니다.
-
-
p를 반환합니다.
getAll(options)
메서드 단계:
-
origin을 settings의 origin으로 설정합니다.
-
origin이 opaque origin이라면, "
SecurityError
"DOMException
으로 거부된 promise를 반환합니다. -
url을 settings의 생성 URL로 설정합니다.
-
options["
url
"] 이 존재한다면, 다음 단계를 실행합니다:-
parsed를 파싱 options["
url
"] 및 settings의 API base URL로 설정합니다. -
this의 관련 글로벌 객체가
Window
이고, parsed가 url과 exclude fragments true로 같지 않으면,TypeError
로 거부된 promise를 반환합니다. -
parsed의 origin과 url의 origin이 동일 출처가 아니면,
TypeError
로 거부된 promise를 반환합니다. -
url을 parsed로 설정합니다.
-
-
p를 새 promise로 설정합니다.
-
다음 단계들을 병렬로 실행합니다:
-
p를 반환합니다.
3.3. set()
메서드
- await cookieStore .
set
(name, value)- await cookieStore .
set
(options) - await cookieStore .
-
쿠키를 작성(생성 또는 수정)합니다.
옵션의 기본값은 다음과 같습니다:
-
Path:
/
-
Domain: 현재 문서 또는 서비스 워커 위치의 도메인과 동일
-
만료일 없음
-
SameSite: strict
-
set(name, value)
메서드 단계:
-
origin을 settings의 origin으로 설정합니다.
-
origin이 opaque origin이라면, "
SecurityError
"DOMException
으로 거부된 promise를 반환합니다. -
url을 settings의 생성 URL로 설정합니다.
-
domain을 null로 설정합니다.
-
path를 "/"로 설정합니다.
-
sameSite를
strict
로 설정합니다. -
partitioned를 false로 설정합니다.
-
p를 새 promise로 설정합니다.
-
다음 단계들을 병렬로 실행합니다:
-
r을 set a cookie를 url, name, value, domain, path, sameSite, 그리고 partitioned로 실행한 결과로 설정합니다.
-
-
p를 반환합니다.
set(options)
메서드 단계:
-
origin을 settings의 origin으로 설정합니다.
-
origin이 opaque origin이라면, "
SecurityError
"DOMException
으로 거부된 promise를 반환합니다. -
url을 settings의 생성 URL로 설정합니다.
-
p를 새 promise로 설정합니다.
-
다음 단계들을 병렬로 실행합니다:
-
r을 set a cookie를 url, options["
name
"], options["value
"], options["expires
"], options["domain
"], options["path
"], options["sameSite
"], 그리고 options["partitioned
"]로 실행한 결과로 설정합니다.
-
-
p를 반환합니다.
3.4. delete()
메서드
- await cookieStore .
delete
(name)- await cookieStore .
delete
(options) - await cookieStore .
-
주어진 이름 또는 이름과 선택적 도메인, 경로로 쿠키를 삭제(만료)합니다.
delete(name)
메서드 단계:
-
origin을 settings의 origin으로 설정합니다.
-
origin이 opaque origin이라면, "
SecurityError
"DOMException
으로 거부된 promise를 반환합니다. -
url을 settings의 생성 URL로 설정합니다.
-
p를 새 promise로 설정합니다.
-
다음 단계들을 병렬로 실행합니다:
-
r을 delete a cookie를 url, name, null, "
/
", 그리고 true로 실행한 결과로 설정합니다.
-
-
p를 반환합니다.
delete(options)
메서드 단계:
-
origin을 settings의 origin으로 설정합니다.
-
origin이 opaque origin이라면, "
SecurityError
"DOMException
으로 거부된 promise를 반환합니다. -
url을 settings의 생성 URL로 설정합니다.
-
p를 새 promise로 설정합니다.
-
다음 단계들을 병렬로 실행합니다:
-
r을 delete a cookie를 url, options["
name
"], options["domain
"], options["path
"], 그리고 options["partitioned
"]로 실행한 결과로 설정합니다.
-
-
p를 반환합니다.
4. CookieStoreManager
인터페이스
CookieStoreManager
는 registration과 연관되어 있으며, 이것은 서비스 워커 등록입니다.
CookieStoreManager
인터페이스는 서비스 워커가 쿠키 변경 이벤트를 구독할 수 있게 합니다. subscribe()
메서드를 사용하여 특정 서비스 워커 등록이 변경 이벤트를 구독하고 있음을 표시해야 합니다.
[Exposed =(ServiceWorker ,Window ),SecureContext ]interface {
CookieStoreManager Promise <undefined >subscribe (sequence <CookieStoreGetOptions >);
subscriptions Promise <sequence <CookieStoreGetOptions >>getSubscriptions ();Promise <undefined >unsubscribe (sequence <CookieStoreGetOptions >); };
subscriptions
4.1.
subscribe()
메서드
- await registration . cookies .
subscribe
(subscriptions) -
쿠키 변경을 구독합니다. 구독은
get()
및getAll()
과 같은 옵션을 사용할 수 있으며, 선택적name
및url
속성을 가질 수 있습니다.구독이 완료되면, 알림은 "
cookiechange
" 이벤트로 서비스 워커의 글로벌 스코프에 전달됩니다:
subscribe(subscriptions)
메서드 단계:
-
registration을 this의 registration으로 설정합니다.
-
p를 새 promise로 설정합니다.
-
다음 단계들을 병렬로 실행합니다:
-
subscription list를 registration에 연결된 쿠키 변경 구독 목록으로 설정한다.
-
각 entry에 대해 subscriptions에서 아래 단계를 실행한다:
-
name을 entry["
name
"]로 설정한다. -
url을 파싱한 entry["
url
"]와 settings의 API 기본 URL의 결과로 설정한다. -
url이 registration의 scope url로 시작하지 않으면, p를 거부하고
TypeError
로 에러를 발생시키고, 이 단계들을 중단한다. -
subscription을 쿠키 변경 구독 (name, url)로 설정한다.
-
subscription list가 이미 subscription을 포함하지 않는다면, subscription을 subscription list에 추가한다.
-
-
-
p를 반환합니다.
4.2.
getSubscriptions()
메서드
- subscriptions = await registration . cookies .
getSubscriptions()
-
이 메서드는 해당 서비스 워커 등록에 대해 생성된 쿠키 변경 구독 목록을 반환하는 promise를 리턴합니다.
getSubscriptions()
메서드 단계:
-
registration을 this의 registration으로 설정합니다.
-
p를 새 promise로 설정합니다.
-
다음 단계들을 병렬로 실행합니다:
-
subscriptions를 registration의 연관된 쿠키 변경 구독 목록으로 설정합니다.
-
result를 새로운 리스트로 설정합니다.
-
subscriptions의 각 subscription에 대해 다음 단계를 실행합니다:
-
-
p를 반환합니다.
4.3.
unsubscribe()
메서드
- await registration . cookies .
unsubscribe
(subscriptions) -
이 메서드를 호출하면 등록된 서비스 워커가 이전에 구독한 이벤트를 더 이상 수신하지 않게 됩니다. subscriptions 인자는
subscribe()
또는getSubscriptions()
의 반환 형식을 따라야 합니다.
unsubscribe(subscriptions)
메서드 단계:
-
registration을 this의 registration으로 설정합니다.
-
p를 새 promise로 설정합니다.
-
다음 단계들을 병렬로 실행합니다:
-
subscription list를 registration의 연관된 쿠키 변경 구독 목록으로 설정합니다.
-
subscriptions의 각 entry에 대해 다음 단계를 실행합니다:
-
-
p를 반환합니다.
4.4.
ServiceWorkerRegistration
인터페이스
ServiceWorkerRegistration
인터페이스는 CookieStoreManager
에 접근할 수 있도록 확장되었으며,
cookies
를 통해 쿠키 변경 구독 인터페이스를 제공합니다.
[Exposed =(ServiceWorker ,Window )]partial interface ServiceWorkerRegistration { [SameObject ]readonly attribute CookieStoreManager cookies ; };
각 ServiceWorkerRegistration
은 연관된 CookieStoreManager
객체를 가집니다.
CookieStoreManager
의
registration은 ServiceWorkerRegistration
의
서비스 워커 등록과 동일합니다.
cookies
getter 단계는 this의 연관된 CookieStoreManager
객체를 반환하는 것입니다.
navigator. serviceWorker. register( 'sw.js' ). then( registration=> { registration. cookies. subscribe([{ name: 'session-id' }]); });
5. 이벤트 인터페이스
5.1. CookieChangeEvent
인터페이스
CookieChangeEvent
는 CookieStore
객체에 대해 Window
컨텍스트에서 디스패치되며, 스크립트에서 볼 수 있는 쿠키 변경이 발생했을 때 동작합니다.
[Exposed =Window ,SecureContext ]interface :
CookieChangeEvent Event {(
constructor DOMString ,
type optional CookieChangeEventInit = {}); [
eventInitDict SameObject ]readonly attribute FrozenArray <CookieListItem >; [
changed SameObject ]readonly attribute FrozenArray <CookieListItem >; };
deleted dictionary :
CookieChangeEventInit EventInit {CookieList ;
changed CookieList ; };
deleted
changed
와 deleted
속성은 초기화된 값을 반환해야 합니다.
5.2.
ExtendableCookieChangeEvent
인터페이스
ExtendableCookieChangeEvent
는 ServiceWorkerGlobalScope
객체에 대해 디스패치되며, 스크립트에서 볼 수 있는
쿠키 변경이 서비스 워커의
쿠키 변경 구독 목록에 매칭될 때 발생합니다.
참고: ExtendableEvent
는 서비스 워커의 모든 이벤트의 상위 인터페이스로 사용되어, 워커 자체가 async 작업을 수행하는 동안 계속 활성 상태를
유지할 수 있게 합니다.
[Exposed =ServiceWorker ]interface :
ExtendableCookieChangeEvent ExtendableEvent {(
constructor DOMString ,
type optional ExtendableCookieChangeEventInit = {}); [
eventInitDict SameObject ]readonly attribute FrozenArray <CookieListItem >; [
changed SameObject ]readonly attribute FrozenArray <CookieListItem >; };
deleted dictionary :
ExtendableCookieChangeEventInit ExtendableEventInit {CookieList ;
changed CookieList ; };
deleted
changed
와 deleted
속성은 초기화된 값을 반환해야 합니다.
6. 글로벌 인터페이스
CookieStore
는 Window
또는 ServiceWorkerGlobalScope
컨텍스트에서 글로벌 스코프의 속성을 통해 스크립트에서 접근합니다.
6.1. Window
인터페이스
[SecureContext ]partial interface Window { [SameObject ]readonly attribute CookieStore cookieStore ; };
Window
는 연관된 CookieStore를 가지며, 이는 CookieStore
입니다.
cookieStore
getter 단계는 this의 연관된 CookieStore를
반환합니다.
6.2. ServiceWorkerGlobalScope
인터페이스
partial interface ServiceWorkerGlobalScope { [SameObject ]readonly attribute CookieStore cookieStore ;attribute EventHandler ; };
oncookiechange
ServiceWorkerGlobalScope
는 연관된 CookieStore를 가지며, 이는 CookieStore
입니다.
cookieStore
getter 단계는 this의 연관된 CookieStore를 반환합니다.
7. 알고리즘
참고: 이는 시간 값이 [ECMAScript]에서 사용하는 표현과 동일합니다.
DOMHighResTimeStamp
를
일자 직렬화하려면,
dateTime을 1970년 1월 1일 00:00:00 UTC 이후 millis 밀리초 후의 날짜 및 시각으로 설정하고
(하루에 정확히 86,400,000 밀리초라고 가정),
dateTime에 대해 바이트 시퀀스를 반환하는데, 이는 Cookies § Dates에 따른
가장 가까운 cookie-date
표현입니다.
7.1. 쿠키 조회
쿠키를 질의한다 는 것은 URL url과 string 또는 null name이 주어진 경우 다음과 같이 한다:
-
Cookies § Retrieval Model에 정의된 단계에 따라 url을 request-uri로 하여 "cookie-string from a given cookie store"를 계산한다. cookie-string 자체는 무시되지만, 중간에 생성된 cookie-list는 이후 단계에서 사용된다.
이 단계에서는 cookie-string이 "non-HTTP" API를 위해 생성된 것으로 간주한다.
-
list를 새로운 list로 설정한다.
-
각 cookie에 대해 cookie-list에서 다음 단계를 실행한다:
-
Assert: cookie의 http-only-flag가 false임을 보장한다.
-
name이 null이 아니면:
-
cookieName을 UTF-8 BOM 없이 디코딩한 cookie의 name의 결과로 설정한다.
-
cookieName이 name과 같지 않다면, 다음 반복으로 넘어간다.
-
item을 CookieListItem을 생성한 cookie의 결과로 설정한다.
-
-
list를 반환한다.
CookieListItem
을
생성한다
는 것은 cookie cookie가 주어졌을 때
다음과 같이 한다:
-
name을 UTF-8 BOM 없이 디코딩한 cookie의 name의 결과로 설정한다.
-
value를 UTF-8 BOM 없이 디코딩한 cookie의 value의 결과로 설정한다.
Note: 한 구현체는 _name_과 _value_ 외의 정보를 노출하는 것으로 알려져 있다.
7.2. 쿠키 설정
쿠키를 설정한다는 것은 url, name, value, 선택적 expires, domain, path, sameSite, 그리고 partitioned 가 주어졌을 때 다음 단계를 실행한다:
-
name 또는 value에 U+003B (;)가 포함되어 있거나, U+0009 TAB을 제외한 어떤 C0 제어 문자 또는 U+007F DELETE가 포함되어 있다면, 실패를 반환한다.
이 문자 제한이 expires, domain, path, sameSite에도 적용되어야 하는지 논의 중임에 유의. [httpwg/http-extensions Issue #1593]
-
name에 U+003D (=)가 포함되어 있다면, 실패를 반환한다.
-
name의 길이가 0이라면:
-
value에 U+003D (=)가 포함되어 있다면, 실패를 반환한다.
-
value의 길이가 0이라면, 실패를 반환한다.
-
value를 바이트 소문자로 변환한 결과가 __host- 또는
__host-http-
,__http-
,__secure-
중 하나로 시작하면, 실패를 반환한다.
-
-
name을 바이트 소문자로 변환한 결과가 __host-http- 또는
__http-
로 시작하면, 실패를 반환한다. -
encodedName을 UTF-8 인코딩한 name의 결과로 설정한다.
-
encodedValue를 UTF-8 인코딩한 value의 결과로 설정한다.
-
encodedName의 바이트 시퀀스 길이와 encodedValue의 바이트 시퀀스 길이의 합이 최대 name/value 쌍 크기를 초과하면, 실패를 반환한다.
-
host를 url의 host로 설정한다.
-
attributes를 새로운 list로 설정한다.
-
domain이 null이 아니라면, 다음 단계를 실행한다:
-
domain이 U+002E (.)로 시작하면, 실패를 반환한다.
-
name을 바이트 소문자로 변환한 결과가 __host-로 시작하면, 실패를 반환한다.
-
domain이 host의 등록 가능한 도메인 접미사도 아니고 host와 같지도 않으면, 실패를 반환한다.
-
parsedDomain을 host 파싱한 domain의 결과로 설정한다.
-
Assert: parsedDomain이 실패가 아님을 보장한다.
-
encodedDomain을 UTF-8 인코딩한 parsedDomain의 결과로 설정한다.
-
encodedDomain의 바이트 시퀀스 길이가 최대 속성 값 크기를 초과하면, 실패를 반환한다.
-
-
expires가 주어지면, append `
Expires
`/expires (날짜 직렬화됨)을 attributes에 추가한다. -
path가 빈 문자열이라면, path를 직렬화된 쿠키 기본 경로로 url에 대해 설정한다.
-
path가 U+002F (/)로 시작하지 않으면 실패를 반환한다.
-
path가 U+002F (/)가 아니고, name을 바이트 소문자화한 값이 `
__host-
`로 시작하면 실패를 반환한다. -
encodedPath를 UTF-8 인코딩한 path의 결과로 설정한다.
-
encodedPath의 바이트 시퀀스 길이가 최대 속성 값 크기를 초과하면 실패를 반환한다.
-
sameSite에 따라 분기한다:
-
partitioned가 true이면, `Partitioned`/``를 attributes에 추가한다.
-
Cookies § 저장 모델에 정의된 단계를 url을 request-uri로, encodedName을 cookie-name으로, encodedValue를 cookie-value로, attributes를 cookie-attribute-list로 하여, 사용자 에이전트가 "쿠키를 수신"할 때 수행한다.
이 단계의 목적상, 새로 생성된 쿠키는 "non-HTTP" API에서 수신된 것으로 간주한다.
-
성공을 반환한다.
참고: 쿠키 저장은 여전히 [RFC6265BIS-14]의 요구사항으로 인해 실패할 수 있지만, 이 단계는 성공으로 간주된다.
7.3. 쿠키 삭제
쿠키를 삭제한다 는 것은 url, name, domain, path, 그리고 partitioned 가 주어졌을 때 다음 단계를 실행한다:
-
expires를 타임스탬프로 표시된 가장 이른 표현 가능한 날짜로 설정한다.
Note: 이 알고리즘에서는 expires의 정확한 값은 중요하지 않으며, 과거의 값이면 충분하다.
-
value를 빈 문자열로 설정한다.
-
set a cookie 알고리즘을 url, name, value, expires, domain, path, "
strict
", partitioned로 실행한 결과를 반환한다.
7.4. 변경 처리
쿠키 변경 처리를 하려면 다음 단계를 실행합니다:
-
모든
Window
window에 대해 다음 단계를 실행합니다:-
changes를 관찰 가능한 변경의 url에 대한 값으로 설정합니다.
-
changes가 비어 있다면 다음 반복으로 이동합니다.
-
글로벌 태스크 큐를 DOM 조작 태스크 소스에 window를 주고, change 이벤트 발행을 "
change
" 이름과 changes 및 window의CookieStore
에 대해 실행합니다.
-
모든 서비스 워커 등록 registration에 대해 다음 단계를 실행합니다:
-
changes를 새로운 집합으로 설정합니다.
-
각 change에 대해 관찰 가능한 변경의 registration의 scope url에 대해 다음 단계를 실행합니다:
-
cookie를 change의 cookie로 설정합니다.
-
각 subscription에 대해 registration의 쿠키 변경 구독 목록에 대해 다음 단계를 실행합니다:
-
change가 포함되어 있지 않으면 관찰 가능한 변경의 subscription의 url에 대해, 다음 반복으로 이동합니다.
-
cookieName을 cookie의 UTF-8 BOM 없이 디코드한 name으로 설정합니다.
-
cookieName이 subscription의 name과 같다면, change를 changes에 추가하고 break합니다.
-
-
-
changes가 비어 있다면 다음 반복으로 이동합니다.
-
changedList와 deletedList를 목록 준비를 changes로 실행한 결과로 설정합니다.
-
기능성 이벤트 발행을 "
cookiechange
" 이름과,ExtendableCookieChangeEvent
타입으로 registration에 다음 속성으로 실행합니다:
-
url의 관찰 가능한 변경은 집합이며, 쿠키 변경 중 쿠키가 쿠키 저장소에서, Cookies § 조회 알고리즘의 1단계 요구사항을 만족하는 경우입니다. url은 request-uri로 사용되며, "non-HTTP" API 용입니다.
쿠키 변경은 쿠키와 타입(변경됨 또는 삭제됨)로 구성됩니다:
type 이름과 changes 및 target으로 change 이벤트 발행을 하려면 다음 단계를 실행합니다:
-
event를 Event 생성을
CookieChangeEvent
타입으로 실행한 결과로 설정합니다. -
event의
type
속성을 type으로 설정합니다. -
event의
bubbles
와cancelable
속성을 false로 설정합니다. -
changedList와 deletedList를 목록 준비를 changes로 실행한 결과로 설정합니다.
-
event의
changed
속성을 changedList로 설정합니다. -
event의
deleted
속성을 deletedList로 설정합니다.
changes로 목록 준비를 하려면 다음 단계를 실행합니다:
-
changedList를 새로운 리스트로 설정합니다.
-
deletedList를 새로운 리스트로 설정합니다.
-
각 change에 대해 changes에 다음 단계를 실행합니다:
-
item을 change의 cookie로 CookieListItem 생성을 실행한 결과로 설정합니다.
-
change의 타입이 변경됨이면 item을 changedList에 추가합니다.
-
그 외에는 다음 단계를 실행합니다:
-
item["
value
"] 를 undefined로 설정합니다.
-
-
-
changedList와 deletedList를 반환합니다.
8. 보안 고려사항
서비스 워커 컨텍스트에서의 쿠키 접근을 제외하면, 이 API는 웹에 새로운 기능을 추가하기 위한 것이 아닙니다.
8.1. 주의!
브라우저의 쿠키 구현은 현재 더 나은 보안과 예기치 않은 오류를 줄이는 방향으로 발전하고 있지만, 현재로서는 쿠키 데이터 보안에 관한 보장이 거의 없습니다.
-
보안되지 않은 오리진은 보안 오리진에서 사용되는 쿠키를 덮어쓸 수 있습니다
-
슈퍼도메인은 서브도메인이 보는 쿠키를 덮어쓸 수 있습니다
-
크로스사이트 스크립팅 공격과 기타 스크립트 및 헤더 인젝션 공격으로도 쿠키를 위조할 수 있습니다
-
쿠키 읽기 작업(스크립트 및 웹 서버 모두)은 쿠키가 어디서 왔는지에 대한 정보를 제공하지 않습니다
-
브라우저는 때때로 쿠키 데이터를 잘라내거나 변환하거나 예기치 않게 제거합니다
-
... 저장 한도에 도달했을 때
-
... 문자 인코딩 차이로 인해
-
... 쿠키의 문법적·의미적 규칙의 차이로 인해
-
이러한 이유로 쿠키 값을 해석할 때 신중을 기하는 것이 가장 좋으며, 쿠키 값을 스크립트, HTML, CSS, XML, PDF 또는 기타 실행 가능한 형식으로 절대 실행하지 마십시오.
8.2. 제한?
이 API는 쿠키 사용을 더 쉽게 하고 그 결과로 쿠키의 추가 사용을 조장할 수 있는 의도치 않은 부작용을 가질 수 있습니다. 비보안 컨텍스트에서 쿠키가 더 많이 사용된다면, 이는 사용자를 위한 웹의 안전성을 저해할 수 있습니다. 이러한 이유로 이 API는 보안 컨텍스트로만 제한되었습니다.
8.3. 보안 쿠키
이 섹션은 비규범적입니다.
이 API는 더 나은 보안 결정을 장려하기 위해 Secure
쿠키에 대해서만 쓰기가 허용됩니다. 하지만 Secure
쿠키로의 마이그레이션을 돕기 위해
비-Secure
쿠키의 읽기도 허용됩니다. 부수적으로, 이 API로 비-Secure
쿠키를 가져오거나 수정하면 해당 쿠키는 자동으로
Secure
로 변경됩니다.
8.4. 예상치 못한 상황
일부 기존 쿠키 동작(특히 도메인 기반, 비보안 컨텍스트에서 보안 컨텍스트에서 읽을 수 있는 쿠키를 설정 가능, 스크립트에서 읽을 수 없는 쿠키를 스크립트로 설정 가능 등)은 웹 보안 관점에서 매우 놀라울 수 있습니다.
기타 예상치 못한 점은 Cookies § Introduction에 문서화되어 있습니다. 예를 들어, 쿠키는 슈퍼도메인(예: app.example.com이 전체 example.com 도메인에 대해 설정)에도 설정될 수 있고, 주어진 도메인 이름의 모든 포트 번호에서 읽을 수 있습니다.
여기에 더해 주요 브라우저마다 쿠키 처리의 역사적 차이가 있었으나, 일부(예: 포트 번호 처리)는 이제 더 일관적으로 처리되고 있습니다.
8.5. 접두사
가능한 경우 예시에서는 __Host-
및 __Secure-
이름 접두사를 사용합니다. 이 접두사는 일부 최신 브라우저에서 비보안 컨텍스트에서의 덮어쓰기, Secure
플래그 없이 덮어쓰기, 그리고
__Host-
의 경우 명시적 Domain
또는 '/' 이외의 Path
속성으로 덮어쓰기를 모두 금지합니다(사실상
same-origin 의미론을 강제). 이러한 접두사는 Secure Cookies를 구현한 브라우저에서는 중요한 보안 이점을 제공하며, 다른 브라우저에서는 특별 의미가 강제되지 않더라도 쿠키가
정상적으로 동작하고 비동기 쿠키 API는 쓰기 작업에서 보안 의미론을 강제합니다. 이 API의 주요 목표는 기존 쿠키와의 상호운영성이므로, 접두사가 없는 쿠키 이름을 사용하는 예시도 일부
포함되어 있습니다.
접두사 규칙은 이 API의 쓰기 작업에서도 강제되지만, 동일 브라우저의 다른 API에서는 강제되지 않을 수 있습니다. 따라서 이러한 강제에 지나치게 의존하는 것은 권장되지 않습니다. 더 널리 채택되기 전까지는 특히 주의해야 합니다.
8.6. URL 범위 지정
서비스 워커 스크립트가 오늘날 직접적으로 쿠키에 접근할 수는 없지만, 서비스 워커 스크립트의 원격 제어 하에 범위 내 HTML 및 스크립트 리소스를 렌더링하여 쿠키 모니터링 코드를 삽입할 수 있습니다. 즉, 서비스 워커의 범위 내에서 쿠키 접근은 기술적으로 이미 가능하지만, 매우 편리하지는 않습니다.
서비스 워커가 /
보다 좁은 범위로 지정된 경우에도, 범위 밖의 경로에 설정된 쿠키를 IFRAME으로 불러올 수 있는 404 페이지 URL을 추측/생성함으로써 읽을 수
있습니다. 동일한 기법을 전체 오리진으로 확장할 수도 있지만, IFRAME을 허용하지 않는 사이트라면 경로 범위 서비스 워커에게 이 기능을 거부할 수 있어, 이러한 제한을 더 논의해보기 전까지는
제거하기를 주저하였습니다.
8.7. 쿠키 기피
개발자 복잡성을 줄이고 임시 테스트 쿠키의 필요성을 없애기 위해, 이 비동기 쿠키 API는 무시될 작업(쓰기/삭제)이면 명시적으로 거부합니다. 마찬가지로 실제 쿠키 데이터가 무시되고 빈 쿠키 저장소처럼 동작하는 경우 읽기 작업도 명시적으로 거부합니다. 이러한 컨텍스트에서 쿠키 변경 관찰을 시도하면 "작동"은 하지만, 읽기 접근이 허용되기 전까지 콜백은 호출되지 않습니다(예: 사이트 권한 변경 등).
오늘날 document.cookie
에서 스크립트 기반 쿠키 쓰기가 허용되지 않는 컨텍스트에서는 일반적으로 아무 동작도 하지 않습니다. 그러나 많은 쿠키 작성 스크립트와 프레임워크는 항상 테스트 쿠키를 쓰고, 그 존재를 확인하여
스크립트 기반 쿠키 쓰기가 가능한지 판단합니다.
마찬가지로, 오늘날 document.cookie
에서 스크립트 기반 쿠키 읽기가 허용되지 않는 컨텍스트에서는 일반적으로 빈 문자열을 반환합니다. 하지만 협력하는 웹 서버는 서버 기반 쿠키 쓰기/읽기가 동작하는지 확인하여 스크립트에 알릴 수
있고(스크립트는 여전히 빈 문자열을 받지만), 이를 통해 스크립트 기반 쿠키 읽기가 불가능함을 추론할 수 있습니다.
9. 프라이버시 고려사항
9.1. 쿠키 삭제
이 섹션은 비규범적입니다.
사용자가 오리진의 쿠키를 삭제할 때, 사용자 에이전트는 해당 오리진의 모든 저장소(서비스 워커, DOM 접근 저장소 등)도 함께 삭제해야 합니다. 이는 웹사이트가 사용자가 삭제를 요청한 후에도 영구 저장소에서 사용자 식별자를 복구하는 것을 방지하기 위함입니다.
감사의 글
이 API의 초기 제안을 만든 Benjamin Sittler에게 감사합니다.
그리고 Adam Barth, Alex Russell, Andrea Marchesini, Andrew Williams, Anne van Kesteren, Ayu Ishii, Ben Kelly, Craig Francis, Daniel Appelquist, Daniel Murphy, Domenic Denicola, Elliott Sprehn, Fagner Brack, Idan Horowitz, Jake Archibald, Joel Weinberger, Joshua Bell, Kenneth Rohde Christiansen, Lukasz Olejnik, Marijn Kruisselbrink, Mike West, Raymond Toy, Rupin Mittal, Tab Atkins, Victor Costan 등 현행 표준을 만드는 데 도움을 주신 분들께도 많은 감사를 드립니다.
이 현행 표준은 Dylan Cutler(Google, dylancutler@google.com)가 작성하였습니다.
지적 재산권
Copyright © WHATWG (Apple, Google, Mozilla, Microsoft). 이 저작물은 크리에이티브 커먼즈 저작자 표시 4.0 국제 라이선스에 따라 라이선스가 부여됩니다. 일부 소스 코드에 통합된 부분의 경우, 소스 코드에서는 BSD 3-Clause 라이선스에 따라 라이선스가 부여됩니다.