프라이빗 네트워크 액세스

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

이 버전:
https://wicg.github.io/private-network-access/
이슈 추적:
GitHub
명세 내 인라인
편집자:
(Google)
이전 편집자:
(Google)

초록

이 문서는 Fetch와 HTML에 대한 수정 사항을 명시하며, 이는 클라이언트의 내부 네트워크에 있는 장치와 서버가 의도치 않게 웹 전체에 노출되는 것과 관련된 위험을 완화하기 위한 것이다.

이 명세는 이전에 CORS-RFC1918로 알려져 있었다.

이 문서의 상태

이 명세는 Web Platform Incubator Community Group에 의해 공개되었다. 이는 W3C 표준이 아니며 W3C 표준화 트랙에도 있지 않다. W3C 커뮤니티 기여자 라이선스 계약(CLA)에 따라 제한적인 옵트아웃 및 기타 조건이 적용된다는 점에 유의하라. W3C 커뮤니티 및 비즈니스 그룹에 대해 자세히 알아보라.

1. 소개

이 절은 규범적이지 않다.

[RFC1918]은 20년 넘게 "private" 인터넷 주소와 "public" 인터넷 주소의 구별을 명시해 왔지만, 사용자 에이전트는 이 둘을 서로 분리하는 데 큰 진전을 이루지 못했다. 공개 인터넷의 웹사이트는 내부 장치와 서버에 요청을 만들 수 있으며, 이는 [DRIVE-BY-PHARMING], [SOHO-PHARMING][CSRF-EXPLOIT-KIT]에 문서화된 것과 같은 사용자 라우터 공격을 포함하여 여러 악의적 동작을 가능하게 한다.

여기에서는 이러한 종류의 공격에 대한 완화책을 제안한다. 이 완화책은 내부 장치가 공개 인터넷으로부터의 요청에 명시적으로 옵트인하도록 요구한다.

1.1. 목표

전체적인 목표는 사용자 에이전트가 사용자의 로컬 인트라넷에서 실행 중인 장치나 사용자의 기기에서 직접 실행 중인 서비스에 대한 공격을 부주의하게 가능하게 하지 않도록 하는 것이다. 예를 들어, 다음에 대한 공격을 완화하고자 한다:

1.2. 예제

1.2.1. 기본적으로 안전

MegaCorp Inc의 라우터에는 꽤 심각한 CSRF 취약점이 있어서 http://admin:admin@router.local/set_dns로 이동하고 여러 GET 매개변수를 전달하면 DNS 설정을 변경할 수 있다. 이런!

다행히도 MegaCorp Inc의 라우터는 공개 인터넷으로부터의 요청에 관심이 없고, 이를 활성화하기 위한 특별한 노력도 하지 않았다. 이는 악의적 요청이 라우터가 무시하는 CORS-preflight request를 생성하므로 취약점의 범위를 크게 완화한다. 더 자세히 살펴보자:

다음 HTML을 포함하는 https://csrf.attack/이 주어졌다고 하자:

<iframe href="https://admin:admin@router.local/set_dns?server1=123.123.123.123">
</iframe>

router.local은 멀티캐스트 DNS의 마법을 통해 라우터 주소로 확인되며 [RFC6762], 사용자 에이전트는 이를 private으로 기록한다. csrf.attackpublic address로 확인되었으므로, 요청은 CORS-preflight request를 트리거한다:

OPTIONS /set_dns?... HTTP/1.1
Host: router.local
Access-Control-Request-Method: GET
Access-Control-Request-Private-Network: true
...
Origin: https://csrf.attack

라우터는 이 OPTIONS 요청을 수신하며, 가능한 안전한 응답이 여러 가지 있다:

  • OPTIONS를 전혀 이해하지 못하면 50X 오류를 반환할 수 있다. 그러면 프리플라이트가 실패하고 실제 GET은 절대 발행되지 않는다.

  • OPTIONS를 이해하더라도, 응답에 Access-Control-Allow-Private-Network 헤더를 포함하지 않을 수 있다. 그러면 프리플라이트가 실패하고 실제 GET은 절대 발행되지 않는다.

  • 충돌할 수도 있다. 충돌은 세련되지는 않지만 꽤 안전하다.

1.2.2. 옵트인

MegaCorp Inc의 일부 장치는 여러 이유로 공개 인터넷과 실제로 통신해야 한다. 이들은 CORS-preflight request에 대한 응답으로 적절한 CORS 헤더를 보내 인터넷으로부터 요청을 받는 데 명시적으로 옵트인할 수 있다.

공개 인터넷의 웹사이트가 장치에 요청을 만들면, 사용자 에이전트는 요청자가 public이고 라우터가 private임을 판단한다. 이는 요청이 위와 마찬가지로 CORS-preflight request를 트리거한다는 뜻이다.

장치는 프리플라이트 요청에 대한 응답으로 올바른 헤더를 보내 접근을 명시적으로 허가할 수 있다. 위 요청의 경우 다음과 같을 수 있다:

HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://public.example.com
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
Access-Control-Allow-Private-Network: true
Content-Length: 0
...
MegaCorp Inc.는 https://go/에서 내부 링크 단축 서비스를 운영하며, 직원들은 이러한 링크를 서로 이메일로 자주 보낸다. 이메일 서버는 직원들이 사무실에 없을 때에도 일할 수 있도록 public address에 호스팅되어 있다. 사려 깊군!

https://mail.mega.corp/에서 https://go/* 링크를 클릭하면, CORS-preflight request가 트리거된다. 이는 public address에서 private address로의 요청이기 때문이다:

OPTIONS /short-links-are-short-after-shortening HTTP/1.1
Host: go
Access-Control-Request-Method: GET
Access-Control-Request-Private-Network: true
...
Origin: https://mail.mega.corp

직원들이 예상대로 이러한 링크를 계속 탐색할 수 있도록, MegaCorp는 프라이빗 네트워크 요청을 허용하기로 선택한다:

HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://mail.mega.corp
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
Access-Control-Allow-Private-Network: true
Content-Length: 0
...

하지만 MegaCorp의 유출 방지 부서는 이 접근이 외부 사람들이 단축기가 반환하는 임의의 리다이렉트 위치를 읽을 수 있게 할까 봐 걱정한다. 그들은 https://go/shortlink가 유출되는 것은 대체로 체념하지만, 대상(https://sekrits/super-sekrit-project-with-super-sekrit-partner)까지 유출된다면 참으로 슬플 것이다.

MegaCorp의 단축 링크 엔지니어들은 이러한 잠재적 실패를 피하기 위해 프리플라이트에 대해서만 CORS 헤더를 반환하도록 주의한다. "실제" 탐색은 CORS 헤더를 요구하지 않으며, 그들은 실제로 교차 출처 요청을 CORS-same-origin인 것처럼 지원하고 싶어 하지 않는다:

// Request:
GET /short-links-are-short-after-shortening HTTP/1.1
Host: go
...

// Response:
HTTP/1.1 301 Moved Permanently
...
Location: https://sekrits/super-sekrit-project-with-super-sekrit-partner

탐색은 정상적으로 진행되지만, mail.mega.corp는 응답과 CORS-same-origin으로 간주되지 않는다.

1.2.4. 혼합 콘텐츠

MegaCorp Inc의 일부 장치는 고유한 출처가 없어 보안 채널(예: HTTPS)을 통해 연결하지 못한다. 그러나 이러한 장치도 여전히 공개 웹사이트와 통신하기를 원할 수 있다. 사용자가 명시적으로 허용하면, 보안 공개 웹사이트와의 비보안 연결에 옵트인할 수 있다.

공개 인터넷의 potentially trustworthy origin을 가진 웹사이트가 장치에서 데이터를 요청하면, 사용자 에이전트는 요청자를 public으로, 장치를 private(potentially trustworthy origin가 아님)으로 인식한다. 이는 CORS-preflight request와 사용자에게 표시되는 권한 프롬프트를 모두 트리거한다(올바른 프리플라이트 응답을 받은 뒤).

웹사이트는 fetch() API 옵션으로 IPAddressSpace를 명시적으로 주장해야 한다:

fetch("http://router.local/ping", {
  targetAddressSpace: "private",
});

장치는 프리플라이트 응답 헤더에서 권한을 명시적으로 표시하고 고유한 장치 ID와 사용자가 이해하기 쉬운 장치 이름을 제공하여 접근을 허가할 수 있다. 위 요청에 대한 응답 예는 다음과 같다:

HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://mail.mega.corp
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
Access-Control-Allow-Private-Network: true
Private-Network-Access-ID: 01:23:45:67:89:0A
Private-Network-Access-Name: userA’s MegaCorp device
Content-Length: 0
...

권한 프롬프트가 나타나며, 장치 헤더의 ID와 이름을 표시한다. 사용자가 권한을 부여하면 요청이 진행된다.

2. 프레임워크

2.1. IP 주소 공간

IPAddressSpace를 다음과 같이 정의한다:

enum IPAddressSpace { "public", "private", "local" };

모든 IP 주소는 IP 주소 공간에 속하며, 이는 세 가지 다른 값 중 하나일 수 있다:

  1. local: 로컬 호스트만 포함한다. 다시 말해, 모든 장치마다 대상이 달라지는 주소이다.

  2. private: 현재 네트워크 내에서만 의미가 있는 주소를 포함한다. 다시 말해, 네트워크 위치에 따라 대상이 달라지는 주소이다.

  3. public: 그 밖의 모든 주소를 포함한다. 다시 말해, IP 네트워크상 전 세계 모든 장치에서 대상이 동일한 주소이다.

편의를 위해 다음 용어도 추가로 정의한다:

  1. local address는 그 IP 주소 공간local인 IP 주소이다.

  2. private address는 그 IP 주소 공간private인 IP 주소이다.

  3. public address는 그 IP 주소 공간public인 IP 주소이다.

IP 주소 공간 lhs는 다음 조건 중 어느 하나가 참이면 IP 주소 공간 rhs보다 덜 공개적이다:

  1. lhslocal이고 rhsprivate 또는 public인 경우.

  2. lhsprivate이고 rhspublic인 경우.

IP 주소 addressIP 주소 공간을 결정하려면, 다음 단계를 실행한다:

  1. address::ffff:0:0/96 "IPv4-mapped Address" 주소 블록에 속하면, address를 그 안에 포함된 IPv4 주소로 대체한다.

  2. Non-public IP address blocks" 표의 각 row에 대해:

    1. addressrow의 주소 블록에 속하면, row의 주소 공간을 반환한다.

  3. public을 반환한다.

비공개 IP 주소 블록
주소 블록 이름 참조 주소 공간
127.0.0.0/8 IPv4 루프백 [RFC1122] local
10.0.0.0/8 사설 사용 [RFC1918] private
100.64.0.0/10 Carrier-Grade NAT [RFC6598] private
172.16.0.0/12 사설 사용 [RFC1918] private
192.168.0.0/16 사설 사용 [RFC1918] private
198.18.0.0/15 벤치마킹 [RFC2544] local
169.254.0.0/16 링크 로컬 [RFC3927] private
::1/128 IPv6 루프백 [RFC4291] local
fc00::/7 고유 로컬 [RFC4193] private
fe80::/10 링크 로컬 유니캐스트 [RFC4291] private
::ffff:0:0/96 IPv4 매핑 [RFC4291] 매핑된 IPv4 주소 참고

사용자 에이전트는 관리자 또는 사용자 설정을 통해 특정 IP 주소 블록의 address space을 재정의하도록 허용할 수 있다. 이는 예컨대 위 알고리즘에 따르면 대부분의 IP 주소가 public으로 간주되는 IPv6 인트라넷을 보호하는 데 유용할 수 있으며, 대신 사용자 에이전트가 인트라넷을 private으로 취급하도록 설정할 수 있다.

Note: 169.254.0.0/16과 같은 링크 로컬 IP 주소는 private으로 간주된다. 이러한 주소는 네트워크 링크의 모든 장치에서 동일한 대상을 식별할 수 있기 때문이다. 이 명세의 이전 버전에서는 이를 대신 local로 간주했다.

Note: 링크 로컬 IP 주소는 링크 간에 공유되면 의미를 잃는다. 이는 비공개 IP 주소와 근본적으로 다르지 않으며, 이들 모두는 일정 정도의 지역성을 가지고 그 범위를 넘어서면 모호해진다. 다만 이는 혼동된 대리자 문제의 특정한 위험을 제기한다. [LINK-LOCAL-URI]는 URI에서 링크 로컬 IP 주소를 위한 구문을 정의함으로써 이 문제를 해결하려고 한다.

Note:IP 주소 공간의 내용은 한때 IANA Special-Purpose Address Registries ([IPV4-REGISTRY][IPV6-REGISTRY])와 그 안에 정의된 Globally Reachable 비트에 따라 결정되었다. 이는 명세 이슈 #50에 설명된 바와 같이, 우리의 용도에는 부정확한 신호로 판명되었다.

이 주소들에 대한 접근이 완전히 차단되면 IPv4 매핑 IPv6 주소에 대한 특별 사례를 제거한다. [Issue #36]

2.2. 프라이빗 네트워크 요청

request (request)는, requestcurrent urlhostrequestpolicy containerIP 주소 공간보다 덜 공개적인 IP 주소 공간을 가진 IP 주소에 매핑되면 private network request이다.

IP 주소를 세 가지 넓은 주소 공간으로 분류하는 것은 불완전하고 이론적으로 타당하지 않은 접근이다. 이는 두 네트워크 엔드포인트가 자유롭게 통신할 수 있어야 하는지, 다시 말해 엔드포인트 A가 엔드포인트 C의 사용자 에이전트를 거쳐 피벗하지 않고 엔드포인트 B에서 도달 가능한지를 판단하기 위해 사용하는 대리 지표이다.

이 접근에는 몇 가지 결함이 있다:

그럼에도 이 명세는 네트워크 구성이 그다지 복잡하지 않은 대부분의 웹 사용자에게 광범위하게 영향을 주는 보안 문제에 대한 실용적인 해결책을 제공하는 것을 목표로 한다.

private network requests의 정의는 current urlhostpublic이 아닌 IP 주소 공간을 가진 IP 주소에 매핑되는 모든 교차 출처 요청을 포함하도록 확장될 수 있다. 이는 프라이빗 네트워크의 악의적 서버가 다른 서버를 공격하지 못하게 할 것이다. 이러한 변경을 출시하는 데 필요한 노력은 현재로서는 보상에 비해 가치가 없다고 판단된다. 이는 나중에 점진적 개선으로 출시할 수 있다. [Issue #39]

NOTE: 일부 private network requests는 다른 것보다 보호하기 더 어렵다. 자세한 내용은 § 4.4 출시 어려움을 참고하라.

2.3. 추가 CORS 헤더

Access-Control-Request-Private-Networkrequestprivate network request임을 나타낸다.

Access-Control-Allow-Private-Network는 리소스가 외부 네트워크와 안전하게 공유될 수 있음을 나타낸다.

Note: 이 헤더들은 한때 Access-Control-Request-Local-NetworkAccess-Control-Allow-Local-Network로 간단히 명시되었으나, 호환성 영향 때문에 이 결정은 되돌려졌다. 자세한 내용은 이슈 #91을 참고하라.

Private-Network-Access-Name는 프라이빗 네트워크 접근 권한 프롬프트에서 사용자에게 사람이 이해하기 쉬운 이름을 제공하려고 시도한다.

Private-Network-Access-ID 헤더는 IP 주소 간 동일한 장치를 식별하기 위해 PrivateNetworkAccessPermissionDescriptor에서 사용된다.

2.4. treat-as-public-address 콘텐츠 보안 정책 지시문

treat-as-public-address 지시문은 문서가 실제로는 private addresslocal address에서 제공되었더라도, 마치 public address에서 제공된 것처럼 사용자 에이전트가 취급하도록 지시한다. 즉, 비공개 문서가 프리플라이트 없이 다른 비공개 문서에 연락할 수 있는 권한을 내려놓는 메커니즘이다.

이 지시문의 구문은 다음 ABNF 문법으로 설명된다:

directive-name  = "treat-as-public-address"
directive-value = ""

이 지시문은 보고 요구사항이 없다. Content-Security-Policy-Report-Only 헤더나 meta 요소 내에서 전달되면 완전히 무시된다.

이 지시문의 초기화 알고리즘은 다음과 같다. 환경 설정 객체 (context), Response (response), 그리고 policy (policy)가 주어졌을 때:

  1. policydisposition이 "enforce"이면, contextpolicy containerIP 주소 공간public으로 설정한다.

2.5. 기능 감지

이 명세의 이전 버전은 addressSpace enum 속성을 DocumentWorkerGlobalScope에 추가할 것을 제안했으나, 지문 채취 우려 때문에 제거되었다 (이슈 #21 참고).

문서는 UA가 이 명세를 구현하는지 여부에 따라 다르게 동작해서는 안 된다. 모든 문서는 구현한다고 가정해야 한다.

2.6. 권한 프롬프트

[Issue#23]의 논의에 따라, 혼합 콘텐츠 검사를 완화하기 위해 프라이빗 네트워크 접근 권한 프롬프트가 도입되었다.

이 권한의 목표는 공개 웹사이트가 HTTP를 통해 로컬 네트워크 서버와 통신할 수 있도록 허용하는 것이다. 그렇지 않으면 이는 보안 컨텍스트 제한과 혼합 콘텐츠 검사에 의해 방지될 것이다. 프라이빗 네트워크 서버를 HTTPS로 마이그레이션하는 것은 실제로 종종 어렵고, 때로는 불가능하다는 것이 입증되었다.

fetch() 옵션 bag에 새 매개변수가 추가된다:

fetch("http://router.local/ping", {
  targetAddressSpace: "private",
});

이는 스킴이 비보안이더라도 fetch를 허용하고 대상 서버에 대한 연결을 얻도록 브라우저에 지시한다. 새 fetch() API는 하위 호환된다.

이 기능은 일반적으로 혼합 콘텐츠를 우회하는 데 악용될 수 없다는 점에 유의하라. 원격 IP 주소가 targetAddressSpace 옵션 값으로 지정된 IP 주소 공간에 속하지 않으면 요청은 실패한다. 속한다면 CORS 프리플라이트 요청이 전송된다. 대상 서버는 다음 두 헤더로 보강된 CORS 프리플라이트 응답으로 응답한다:

Private-Network-Access-Name: <some human-readable device self-identification>
Private-Network-Access-ID: <some unique and stable machine-readable ID, such as a MAC address>

예를 들면:

Private-Network-Access-Name: "My Smart Toothbrush"
Private-Network-Access-ID: "01:23:45:67:89:0A"

Private-Network-Access-ID는 콜론으로 구분된 6개의 16진수 바이트로 표시되는 48비트 값이어야 한다. Private-Network-Access-Name는 [ECMAScript] 정규식 /^[a-z0-9_-.]+$/와 일치하는 문자열인 유효한 이름이어야 한다. 248은 이름의 UTF-8 코드 단위 최대 개수이다.

그런 다음 대상 장치에 접근할 권한을 요청하는 프롬프트가 사용자에게 표시된다. -Name 헤더는 출처(흔히 원시 IP 리터럴) 대신 또는 추가로 사용자에게 친숙한 문자열을 표시하는 데 사용된다. -ID 헤더는 권한의 키로 사용되며 IP 주소 간 장치를 인식하는 데 사용된다. 실제로 DHCP가 널리 사용되므로 장치가 정기적으로 IP 주소를 변경할 가능성이 높고, 우리는 교차 장치 혼동과 권한 피로를 모두 피하고자 한다.

사용자가 권한 부여를 결정하면 fetch는 계속된다. 그렇지 않으면 실패한다. 그런 다음 권한은 지속된다. 동일한 initiator 출처에 속하며 동일한 서버 (원시 IP 주소를 사용하는 경우에는 다른 출처일 수도 있음)에 접근하려는 의도를 선언하는 다음 문서는 권한 프롬프트를 트리거하지 않는다. 초기 CORS 프리플라이트 응답은 동일한 ID를 전달하고, 브라우저는 문서가 이미 서버에 접근할 권한을 가지고 있음을 인식한다.

기존 -Name 또는 -ID가 없으면, 프롬프트는 IP 주소만 표시하여 나타난다. 사용자가 권한 부여를 결정하면 fetch는 계속된다. 권한은 임시 권한으로 저장되며 현재 창 프로세스 동안만 지속된다.

3. 통합

이 절은 규범적이지 않다.

이 문서는 위 예제에 개략적으로 제시된 완화책을 구현하기 위해 다른 명세에 대한 여러 수정을 제안한다. 이러한 통합은 명확성을 위해 여기서 개요를 제시하지만, 외부 문서가 규범적 참조이다.

3.1. 보안 컨텍스트 제한

UA는 프라이빗 서버가 프리플라이트를 통해 그러한 요청에 옵트인하더라도, non-secure public 컨텍스트가 private addresses의 리소스를 요청하도록 허용해서는 안 된다. private 리소스에 요청을 만드는 것은 요청을 시작하는 client의 무결성을 보장함으로써 완화되는 위험을 제시한다. 특히 네트워크 공격자가 비보안 출처에 대한 엔드포인트의 동의를 쉽게 악용할 수 없어야 한다.

혼합 콘텐츠 검사 [MIXED-CONTENT-2]는 보안 컨텍스트가 HTTP를 통해 요청을 만드는 것을 방지하므로, 이 제한은 프라이빗 네트워크 서버가 HTTPS로 마이그레이션해야 하는 것처럼 보인다. 이는 종종 어렵거나 불가능하다. 사용자 동의가 주어지면 보안 컨텍스트가 HTTP를 통해 프라이빗 네트워크로 요청을 만들 수 있도록 새 권한 프롬프트가 도입된다.

3.2. Permissions와의 통합

이 문서는 강력한 기능을 정의하며, 이는 name "private-network-access"로 식별된다. 이는 다음 타입을 재정의한다:

permission descriptor type
permission descriptor type"private-network-access" 기능은 기본 permission descriptor type에서 상속하는 다음 WebIDL 인터페이스로 정의된다:
dictionary PrivateNetworkAccessPermissionDescriptor
    : PermissionDescriptor {
  DOMString id;
};

3.3. Mixed Content와의 통합

Should fetching request be blocked as mixed content?는 다음 조건을 allowed 조건 중 하나에 추가하도록 수정된다:
  1. requestoriginpotentially trustworthy origin가 아니고, requesttarget IP address spaceprivate 또는 local인 경우.

3.4. Fetch와의 통합

이 문서는 Fetch에 몇 가지 변경을 제안하며, 그 의미는 다음과 같다. private network requests는 그 clientsecure context이고 또한 대상 출처에 대한 CORS-preflight request가 성공한 경우에만 허용된다. 요청이 혼합 콘텐츠로 차단되었을 경우에도, 웹사이트가 프라이빗 네트워크에 접근하려는 의도를 명시하고 사용자가 권한을 부여하면 허용될 수 있다.

Note: 여기에는 탐색도 포함된다. 탐색은 실제로 하위 리소스 요청보다 덜 은밀하지만 CSRF 공격을 트리거하는 데 사용될 수 있다.

Note: [FETCH]는 아직 DNS 확인의 세부사항을 Fetch 알고리즘에 통합하지 않았지만, 이 명세에 충분한 연결 획득 알고리즘을 정의한다. Private Network Access 검사는 새로 획득된 연결에 적용된다. Happy Eyeballs([RFC6555], [RFC8305])와 같은 복잡성 때문에, 이러한 검사는 여러 IP 주소가 IP 주소 공간 경계에 걸쳐 있는 호스트에서 비결정적으로 통과하거나 실패할 수 있다.

3.4.1. CORS 프리플라이트

HTTP fetch 알고리즘은 private network requestssecure contexts에서 시작된 경우 모두 프리플라이트가 트리거되도록 조정되어야 한다.

여기서의 주요 문제는 응답의 IP 주소 공간HTTP-network fetch에서 연결을 획득하기 전까지는 알려지지 않는다는 점이다. 이는 CORS-preflight fetch 아래 계층에 있다.

3.4.2. 가져오기

다음은 잠재적 해결책의 개요이다:

  1. Connection 객체에는 새 IP 주소 공간 속성이 주어지며, 초기값은 null이다. 이는 WebSocket 연결에도 적용된다.

  2. 사용자 에이전트의 connection poolconnection을 추가하기 직전에, 연결 획득 알고리즘에 새 단계가 추가된다:

    1. connectionIP 주소 공간connection의 원격 엔드포인트 IP 주소에 대해 IP 주소 공간 결정 알고리즘을 실행한 결과로 설정한다.

      원격 엔드포인트 개념은 아직 [FETCH]에 명시되어 있지 않으므로, 이는 어느 정도 손짓 설명에 머무른다. [Issue #33]

  3. Request 객체에는 새 target IP address space 속성이 주어지며, 초기값은 null이다.

  4. Response 객체에는 새 IP 주소 공간 속성이 주어지며, 그 값은 IP 주소 공간이고 초기값은 null이다.

  5. Private Network Access 검사 알고리즘을 정의한다. request requestconnection connection이 주어졌을 때:

    1. requestoriginpotentially trustworthy origin이고 requestcurrent URLoriginrequestoriginsame origin이면, null을 반환한다.

    2. requestpolicy container가 null이면 null을 반환한다.

      NOTE: requestpolicy container가 null이면, PNA 검사는 request에 적용되지 않는다. fetch 알고리즘 사용자는 requestclient를 null이 아닌 환경 설정 객체로 설정하되 그 객체가 null이 아닌 policy container를 가지도록 하고 fetchrequestpolicy container를 그에 따라 초기화하게 하거나, requestpolicy container를 null이 아닌 값으로 직접 설정하도록 주의해야 한다.

    3. requesttarget IP address space가 null이 아니면:

      1. Assert: requesttarget IP address spacepublic이 아니다.

      2. connectionIP 주소 공간requesttarget IP address space와 같지 않으면, network error를 반환한다.

      3. null을 반환한다.

    4. connectionIP 주소 공간requestpolicy containerIP 주소 공간보다 덜 공개적이면:

      1. errornetwork error로 둔다.

      2. requestclientsecure context가 아니면(null인 경우 포함), error를 반환한다.

      3. errorIP 주소 공간 속성을 connectionIP 주소 공간으로 설정한다.

      4. error를 반환한다.

    5. null을 반환한다.

  6. fetch 알고리즘은 requestpolicy container가 설정된 직후 다음 단계를 추가하도록 수정된다:

    1. requesttarget IP address spacepublic이면, network error를 반환한다.

  7. HTTP-network fetch 알고리즘은 새로 획득한 connection이 failure가 아님을 확인한 직후 3개의 새 단계를 추가하도록 수정된다:

    1. responseIP 주소 공간connectionIP 주소 공간으로 설정한다.

    2. privateNetworkAccessCheckResultfetchParamsrequestconnection에 대해 Private Network Access 검사를 실행한 결과로 둔다.

    3. privateNetworkAccessCheckResultnetwork error이면, privateNetworkAccessCheckResult를 반환한다.

  8. request request와 boolean makeCORSPreflight가 주어졌을 때 프리플라이트 모드 결정이라는 새 알고리즘을 정의한다:

    1. makeCORSPreflight가 true이고 다음 조건 중 하나가 true이면:

      • request를 사용하여 requestmethod에 대한 method cache entry match가 없고, requestmethodCORS-safelisted method가 아니거나 requestuse-CORS-preflight flag가 설정된 경우.

      • requestheader list를 사용했을 때 header-name cache entry match가 없는 CORS-unsafe request-header names 안의 item이 하나 이상 있는 경우.

      그러면:

      1. requesttarget IP address space가 null이 아니면 "cors+pna"를 반환한다.

      2. 그렇지 않으면 "cors"를 반환한다.

    2. requesttarget IP address space가 null이 아니면 "pna"를 반환한다.

    3. 그렇지 않으면 "none"을 반환한다.

  9. HTTP fetch에서 서비스 워커를 통해 fetch를 처리한 뒤에도 response가 여전히 null일 때 실행되는 기존 단계에 기반하여 HTTP-no-service-worker fetch라는 새 알고리즘을 정의하고, 이를 다음과 같이 약간 수정한다:

    1. preflightModerequestmakeCORSPreflight가 주어졌을 때 프리플라이트 모드 결정을 호출한 결과로 둔다.

    2. 전체 조건 "If makeCORSPreflight is true and ..., Then:"을 다음으로 대체한다:

      1. preflightMode가 "none"이 아니면:

    3. "request가 주어진 상태로 CORS-preflight fetch 실행"을 "requestpreflightMode가 주어진 상태로 CORS-preflight fetch 실행"으로 대체한다

    4. CORS-preflight fetch를 실행한 직후:

      1. preflightResponsenetwork error이면:

        1. preflightResponseIP 주소 공간이 null이면 preflightResponse를 반환한다.

        2. requesttarget IP address spacepreflightResponseIP 주소 공간으로 설정한다.

        3. fetchParams가 주어진 상태로 HTTP-no-service-worker fetch를 실행한 결과를 반환한다.

    5. HTTP-network-or-cache fetch를 실행한 직후:

      1. responsenetwork error이고 responseIP 주소 공간이 non-null이면:

        1. requesttarget IP address spacepreflightResponseIP 주소 공간으로 설정한다.

        2. fetchParams가 주어진 상태로 HTTP-no-service-worker fetch를 실행한 결과를 반환한다.

    Note: 재귀 시 requesttarget IP address space가 null이 아닌 값으로 설정되므로, 이 재귀는 최대 1단계 깊이까지만 가능하다.

  10. CORS-preflight fetch 알고리즘은 새 매개변수 preflightMode(기본값 "cors")를 받도록 조정되고, 새 헤더를 다음과 같이 처리한다:

    1. preflightMode가 true인 경우에만 `Accept` 및 `Access-Control-Request-Headers`를 preflightheader list에 추가한다.

    2. HTTP-network-or-cache fetch를 실행하기 직전:

      1. requesttarget IP address space가 null이 아니면:

        1. preflightheader list에서 "Access-Control-Request-Private-Network"를 "true"로 설정한다.

    3. CORS 검사 직후:

      1. preflightMode가 "pna" 또는 "cors+pna"이면,

        1. Assert: requesttarget IP address space는 null이 아니다.

        2. allow를 "Access-Control-Allow-Private-Network"와 responseheader list가 주어졌을 때 header list values 추출의 결과로 둔다.

        3. allow가 "true"가 아니면 network error를 반환한다.

        4. requestWithoutTargetIpAddressSpacerequest의 복사본으로 두되, 그 target IP address space를 null로 설정한다.

        5. should fetching requestWithoutTargetIpAddressSpace be blocked as mixed content allowed를 반환하면 null을 반환한다.

        6. Private-Network-Access-ID 또는 Private-Network-Access-Name이 null이거나 비어 있으면, targetIdrequesttarget IP address space로 둔다. 권한을 임시 권한으로 저장한 다음 null을 반환한다.

        7. targetId를 "Private-Network-Access-ID"와 responseheader list가 주어졌을 때 header list values 추출의 결과로 둔다.

        8. targetId가 콜론으로 구분된 6개의 16진수 바이트 문자열이 아니면 network error를 반환한다.

        9. targetName을 "Private-Network-Access-Name"와 responseheader list가 주어졌을 때 header list values 추출의 결과로 둔다.

        10. targetName이 [ECMAScript] 정규식 /^[a-z0-9_-.]+$/와 일치하지 않거나 248개를 초과하는 UTF-8 코드 단위를 가지면, network error를 반환한다.

        11. state를 다음 설명자에 대한 사용 권한 요청의 결과로 둔다:

          {
            name: "private-network-access",
            id: targetId,
          }
          
        12. state"denied"이면, network error를 반환한다.

        13. null을 반환한다.

  11. 마지막으로 DNS 리바인딩 공격의 영향을 완화하기 위해(§ 5.3 DNS 리바인딩 참고), CORS-preflight cacheIP 주소 공간 정보를 고려하도록 조정된다:

    1. IP 주소 공간 속성 (null 또는 IP 주소 공간)이 각 cache entry에 추가된다.

    2. 이 새 속성은 새 cache entry 생성 알고리즘에 의해 requesttarget IP address space에서 초기화된다.

    3. 이 새 속성은 cache entry match 알고리즘에서 검사된다:

      1. entryIP 주소 공간requesttarget IP address space와 같다.

3.4.3. Fetch API

Fetch API도 조정되어야 한다.

3.4.4. 금지된 헤더 이름

forbidden request-header 이름 목록에 새 항목이 추가된다: Access-Control-Request-Private-Network.

사용자 에이전트는 다른 CORS 헤더와 마찬가지로 이 헤더에 대한 완전한 제어권을 가져야 한다.

3.5. WebSockets와의 통합

WebSocket 핸드셰이크는 <img> 태그와 대략 같은 기능을 가지므로, 프리플라이트 요청은 WebSocket 핸드셰이크에 앞서 전송되는 것이 좋을 것이다. WebSocket 연결 수립Fetch 알고리즘에 의존한다는 점을 고려하면, 이를 명시하는 데 추가 작업이 필요하지 않을 수도 있다. [Issue #14]

이 명세의 이전 버전은 새 헤더(§ 2.3 추가 CORS 헤더 참고)를 WebSocket 핸드셰이크에 단순히 추가할 것을 제안했다. 그러나 이는 CSRF 공격을 완전히 방어하기에는 충분하지 않을 것이다.

3.6. HTML과의 통합

[FETCH]의 검사를 지원하기 위해, 사용자 에이전트는 네트워크 요청이 이루어지는 컨텍스트의 출처 IP 주소 공간을 기억해야 한다. 이를 위해 [HTML] 명세는 다음과 같이 패치된다:

  1. IP 주소 공간 속성이 policy container struct에 추가된다.

    1. 초기값은 public이다.

  2. policy container 복제 알고리즘에 추가 단계가 더해진다:

    1. cloneIP 주소 공간policyContainerIP 주소 공간으로 설정한다.

  3. fetch 응답에서 policy container 생성 알고리즘에 추가 단계가 더해진다:

    1. resultIP 주소 공간responseIP 주소 공간으로 설정한다.

example.compublic address(예: 123.123.123.123)로 확인된다고 가정하면, https://example.com/document.html로 탐색할 때 생성되는 Document는 그 policy containerIP 주소 공간 속성이 public으로 설정된다.

Document가 이후 about:srcdoc iframe을 삽입하면, 자식 프레임의 Document도 그 policy containerIP 주소 공간 속성이 public으로 설정된다.

반면, example.comlocal address(예: 127.0.0.1)로 확인되면, https://example.com/document.html로 탐색할 때 생성되는 Document는 그 policy containerIP 주소 공간 속성이 local로 설정된다.

3.7. Workers

이 절은 규범적이지 않다.

WorkerGlobalScope는 이미 policy container 필드를 가지고 있고, 이 필드는 fetch 응답에서 policy container 생성 알고리즘을 사용해 채워지므로, 위 Fetch 및 HTML과의 통합은 문서 컨텍스트와 마찬가지로 워커 컨텍스트에도 적용된다.

example.compublic address(예: 123.123.123.123)로 확인된다고 가정하면, https://example.com/worker.js에서 스크립트를 fetch하여 생성된 WorkerGlobalScope는 그 policy containerIP 주소 공간 속성이 public으로 설정된다.

이 워커가 시작한 모든 fetch request연결을 획득하여 private 또는 local 주소 공간의 IP 주소에 연결된다면, 이는 private network request가 된다.

Service Worker soft update 알고리즘은 업데이트된 스크립트를 fetching할 때 유감스럽게도 request client"null"로 설정한다. 이는 온갖 문제를 일으키며, 위에 제시된 private network access check 알고리즘을 방해한다. 실제로 request client가 없어서 policy containerfetch 중에 복사해 올 수 없다. [Issue #83]

4. 구현 고려사항

4.1. file URL은 어디에 들어맞는가?

file URL이 위에서 설명한 public/private 체계에 어떻게 들어맞는지는 완전히 명확하지 않다. 한편으로는 사람들이 악의적 HTML 파일을 로컬에서 열어 스스로 피해를 입는 것을 막으면 좋겠지만, 다른 한편으로는 로컬에서 실행되는 코드는 일관된 위협 모델의 바깥에 어느 정도 놓여 있다.

현재로서는 file URL을 local로 취급하는 쪽으로 조심스럽게 판단하자. 이는 루프백 주소에 있는 무엇이든 로컬 시스템의 일부인 것과 마찬가지로 보이기 때문이다.

구현 경험 이후 이를 재평가한다.

4.2. 프록시

Chromium에서 이 명세를 현재 구현한 방식에서는, 프록시가 자신이 프록시하는 리소스의 address space에 영향을 준다. 구체적으로, 프록시를 통해 가져온 리소스는 프록시의 IP 주소 자체에서 가져온 것으로 간주된다.

public addressfoo.example에서 제공되는 Document가 사용자 에이전트에 의해 private address의 프록시를 통해 가져와지면, 그 Documentpolicy containerIP address spaceprivate으로 설정된다.

Document는 이어서 브라우저가 접근할 수 있는 다른 private addresses로 요청을 만들 수 있게 된다.

이는 웹사이트가 private addresses로 요청을 만들 수 있음을 관찰하여 자신이 프록시되었다는 사실을 알 수 있게 하며, 이는 개인정보 정보 유출이다. 이는 프라이빗 네트워크의 리소스 URL을 정확히 추측해야 하지만, 한 번의 정확한 추측만으로 충분하다.

이는 비교적 드문 경우로 예상되며 추가 완화를 정당화하지는 않는다. 결국 현행 상태에서는 모든 웹사이트가 제한 없이 모든 IP 주소로 요청을 만들 수 있다.

프록시가 브라우저에 "그래도 이 리소스를 public/private로 취급해 달라"고 알려, 프록시 뒤의 IP 주소에 관한 일부 정보를 전달할 수 있는 메커니즘을 탐구해 보는 것은 흥미로울 것이다. 이는 위에서 논의한 CSP 지시문의 형태를 약간 수정한 것일 수 있다.

4.3. HTTP 캐시

Chromium에서 이 명세를 현재 구현한 방식은, 캐시에서 로드되는 리소스의 종류에 따라 HTTP 캐시와 두 가지 주목할 만한 방식으로 상호작용한다.

4.3.1. 주요 리소스

캐시된 response에서 구성된 document는 그 response가 처음 로드된 IP 주소를 기억한다. documentIP address space는 IP 주소에서 새로 파생된다.

일반적인 경우 이는 documentpolicy containerIP address space가 변경 없이 복원됨을 의미한다. 그러나 사용자 에이전트의 구성이 변경된 경우, 파생된 IP address space는 다를 수 있다.

사용자 에이전트가 http://foo.example/로 탐색하여 주요 리소스를 1.2.3.4에서 로드하고 캐시한 다음, 결과 documentpolicy containerIP address spacepublic으로 설정한다.

그런 다음 사용자 에이전트가 재시작되고, 1.2.3.4를 대신 private address로 분류하도록 지정하는 새 구성이 적용된다.

사용자 에이전트가 다시 http://foo.example/로 탐색하고 HTTP 캐시에서 주요 리소스를 로드한다. 결과 documentpolicy containerIP address space는 이제 private으로 설정된다.

4.3.2. 하위 리소스

HTTP 캐시에서 로드된 하위 리소스는 Private Network Access 검사의 대상이다. 이는 아직 위 알고리즘에 반영되어 있지 않은데, 그 검사가 HTTP-network fetch에서만 적용되기 때문이다.

여기서 Chromium의 동작을 명시하고 설명한다. [Issue #75]

보안 영향에 대한 논의는 § 5.6 HTTP 캐시를 참고하라.

4.4. 출시 어려움

Private Network Access는 본질적으로 프라이빗 네트워크에 대한 직접 접근을 더 안전한 사용자 에이전트 중재 대안으로 대체하며 폐기한다. 웹 폐기는 어렵다. Chromium은 이 명세의 일부를 출시하는 과정에서 많은 장애물을 만났다.

특히 private IP address spacenon-secure contexts에서 local IP address space로의 fetch 제한을 출시하는 것은 보상이 낮은 데 비해 특히 어려운 것으로 드러났다. 실제로 이러한 fetch를 악용하려면 공격자가 이미 프라이빗 네트워크에 발판을 가지고 있어야 하며, 이는 공격 난이도를 크게 높인다. 그 결과 Chromium은 이러한 fetch를 제한에서 일시적으로 면제하고, public IP address space에서의 fetch에 집중하기로 선택했다.

5. 보안 및 개인정보 고려사항

5.1. 사용자 중재

이 문서의 제안은 장치가 공개 인터넷으로부터의 접근에 동의하도록 보장할 뿐이다. 사용자 에이전트는 사용자도 그러한 접근에 동의하도록 보장할 수 있다(MAY). 장치 자체가 허용하더라도, 사용자가 그러한 접근을 거부하는 것이 이익일 수 있기 때문이다.

이러한 중재는 명시적 권한 부여, PAKE와 같은 일종의 페어링 절차, 또는 사용자 에이전트가 고안할 수 있는 다른 영리한 인터페이스를 통해 이루어질 수 있다.

5.2. 혼합 콘텐츠

이 문서의 제안이 추가하는 CORS 제한은 혼합 콘텐츠 검사 [MIXED-CONTENT-2]를 불필요하게 만들지 않는다. CORS 프리플라이트 요청을 통해 얻은 장치 동의는 필요하지만 충분하지는 않다.

Note: [MIXED-CONTENT-2]는 보안 컨텍스트가 localhosthost 또는 127.0.0.0/8이나 ::1/128 블록에 있는 IP 주소를 가진 origins에서 리소스를 가져오는 것을 막지 않는다. potentially trustworthy origins의 정의도 참고하라.

위 예외가 아닌 호스트에서 private 또는 local 리소스를 public 페이지에서 가져오려는 개발자는 연결이 안전함을 반드시 보장해야 한다(MUST). 이는 [PLEX]와 같은 방식의 해결책을 포함할 수 있다. 여기서는 사용자별 도메인 이름에 Web PKI 인증서를 발급하고, 그 도메인 이름이 사용자의 프라이빗 네트워크에서만 의미가 있는 private IP 주소로 해석된다.

일부 소비자용 라우터는 DNS 리바인딩 공격에 대해 과도하게 공격적인 보호를 구현하여, non-public IP 주소로 확인되는 DNS 응답을 단순히 차단한다. 이는 [PLEX]와 같은 해결책에 걸림돌이 된다. 우회 방법은 링크된 이슈에서 논의된다. [Issue #23]

이 문제 공간은 이미 몇 차례 탐구된 바 있으며, 어느 시점에 다시 살펴볼 가치가 있어 보인다. 위에서 암시한 것과 같은 페어링 절차나, [SECURE-LOCAL-COMMUNICATION]에서 제기된 아이디어 중 하나를 상상할 수 있다.

5.3. DNS 리바인딩

여기에 설명된 완화책은 특정 리소스를 로드할 때 사용자 에이전트가 실제로 연결하는 IP 주소에 대해 동작한다. 이 검사는 새로 만들어지는 각 연결마다 반드시 수행되어야 한다(MUST). 그렇지 않으면 DNS 리바인딩 공격이 사용자 에이전트를 속여 공개해서는 안 되는 정보를 공개하게 만들 수 있다.

CORS-preflight cache에 대한 수정은 이 공격 벡터를 완화하기 위한 것이다.

5.4. 완화 범위

이 문서의 제안은 프라이빗 웹 서비스에 대한 공격을 완화할 뿐이며, 이를 완전히 해결할 수는 없다. 예를 들어, 라우터의 웹 기반 관리 인터페이스는 자체적으로 CSRF를 방어하도록 설계되고 구현되어야 하며, 이 문서에 명시된 대로 동작하는 UA에 의존해서는 안 된다. 이 문서가 명시하는 완화책은 오늘날 프라이빗 웹 서비스 구현 품질의 현실을 고려할 때 필요하지만, 모든 UA가 이 완화책을 구현하더라도 벤더가 책임에서 면제된다고 생각해서는 안 된다.

5.5. 교차 네트워크 혼동

대부분의 프라이빗 네트워크는 서로 통신할 수 없지만, 이 명세에서는 모두 private IP address space에 속하는 것으로 취급된다. 더 나아가, private addresses는 사용되는 프라이빗 네트워크에서만 의미가 있다. 동일한 IP 주소가 서로 다른 두 네트워크에서 전혀 다른 장치를 가리킬 수 있다.

이는 교차 네트워크 공격의 문을 연다:

이 공격들은 새로운 것이 아니다. 이는 단지 이 명세의 한계를 보여주는 예일 뿐이다.

가능한 완화책은 네트워크 변경을 감지하고 이전 네트워크에 특정한 상태를 지우는 것을 요구할 것이다. 이를 완전히 일반적인 방식으로 수행하는 것은 모든 상태를 지우는 것 외에는 불가능할 가능성이 높다. 어쩌면 실용적인 절충점에 도달할 수 있을 것이다. [Issue #28]

5.6. HTTP 캐시

5.6.1. 하위 리소스에 검사 적용

다음 내용은 더 이상 정확하지 않다. 구현 경험은 캐시와의 통합이 CSRF 공격으로부터 네트워크 리소스를 보호하는 데에도 유용하다는 점을 드러냈다. 이 절은 다시 작성되어야 한다. [Issue #75]

캐시된 하위 리소스는 현재 이 명세로 보호되지 않는다. HTTP 캐시가 HTTP-network-or-cache fetchPrivate Network Access 검사 알고리즘에서 사용할 수 있는 출처 IP 주소를 기억하더라도 그렇다.

이 명백한 불일치를 수정하는 것이 좋은 생각일 수는 있지만, 이 명세의 주된 목표인 CSRF 공격 방지와 직접 관련되지는 않는다.

기껏해야 악의적인 공개 웹사이트가 사용자가 과거에 특정 프라이빗 웹사이트를 방문했는지 여부를 확인할 수 있을 수 있다. 사용자 개인정보에 대한 이 공격은 현행 상태보다 나쁘지 않다.

또한 HTTP 캐시 파티셔닝 때문에, 하위 리소스는 악성 공격자가 cache entrynetwork partition key를 복제하는 데 성공한 경우에만 캐시에서 로드될 수 있다. 공격자가 이를 달성할 수 있는 한 가지 방법은 DNS를 조작하여(§ 5.3 DNS 리바인딩도 참고) 캐시된 리소스를 처음 삽입한 최상위 사이트를 가장하는 것이다.

사용자 에이전트가 192.168.1.1에서 제공되는 http://router.example로 탐색한다. 웹사이트는 http://router.example/$BRAND-logo.png에서 로고를 삽입하고, 이는 캐시된다.

그런 다음 악의적인 공격자는 router.example을 공격자가 제어하는 공개 IP 주소로 리바인딩하고, 어떻게든 사용자를 속여 http://router.example를 다시 방문하게 한다. 악성 웹사이트는 로고를 삽입하려고 시도하고, 로드가 성공했는지 관찰한다. 성공했다면, 공격자는 사용자의 라우터 브랜드를 알아낸 것이다.

5.6.2. HTTP 캐시 오염

이 명세는 공개 웹사이트로부터의 요청을 받는 프라이빗 네트워크 서버를 보호하는 것을 목표로 하지만, DNS 리바인딩은 인증되지 않은 리소스의 캐시 오염을 통해 유사한 공격을 수행하는 데 사용될 수 있다.

http://router.com으로 가장한 공격자는 http://router.com/totally-legit.js에 악성 스크립트를 캐시할 수 있다. 나중에 사용자가 http://router.com/로 탐색하면, 페이지가 오염된 스크립트를 요청하고 less public IP address space에서 공격자 코드를 실행할 수 있다.

이 공격은 캐시 파티셔닝으로 부분적으로 완화된다. 캐시 파티셔닝은 공격자가 리소스를 캐시하기 전에 최상위 브라우징 컨텍스트를 http://router.com/로 탐색해야 하도록 만들며, 이는 은밀하지 않다. 또한 이는 Private Network Access에 특유한 것이 아니라, 평문 HTTP에 인증과 무결성 보호가 없다는 증상의 하나이다.

6. IANA 고려사항

Content Security Policy Directive 레지스트리는 다음 지시문과 참조로 갱신되어야 한다 [RFC7762]:

treat-as-public-address

이 문서(§ 2.4 treat-as-public-address 콘텐츠 보안 정책 지시문 참고)

7. 감사의 말

Ryan Sleevi, Chris Palmer, Justin Schuh와의 대화는 이 제안의 윤곽을 구체화하는 데 도움이 되었다. 바라건대 그들이 이를 너무 싫어하지 않기를 바란다. Mathias Karlsson은 낙타의 등을 부러뜨린 마지막 지푸라기라는 미심쩍은 영예를 가지고 있으며, 그 결과 이어진 스레드에 대한 Brian Smith의 기여는 늘 그렇듯 유용했다.

색인

이 명세가 정의하는 용어

참조로 정의되는 용어

참고문헌

규범적 참고문헌

[CSP3]
Mike West; Antonio Sartori. Content Security Policy Level 3. URL: https://w3c.github.io/webappsec-csp/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[MIXED-CONTENT]
Emily Stark; Mike West; Carlos IbarraLopez. Mixed Content. URL: https://w3c.github.io/webappsec-mixed-content/
[PERMISSIONS]
Marcos Caceres; Mike Taylor. Permissions. URL: https://w3c.github.io/permissions/
[RFC7762]
M. West. Initial Assignment for the Content Security Policy Directives Registry. 2016년 1월. Informational. URL: https://www.rfc-editor.org/rfc/rfc7762
[SECURE-CONTEXTS]
Mike West. Secure Contexts. URL: https://w3c.github.io/webappsec-secure-contexts/
[SERVICE-WORKERS]
Jake Archibald; Marijn Kruisselbrink. Service Workers. URL: https://w3c.github.io/ServiceWorker/
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/
[WEBSOCKETS]
Adam Rice. WebSockets Standard. Living Standard. URL: https://websockets.spec.whatwg.org/

정보 제공 참고문헌

[AVASTIUM]
Avast: A web-accessible RPC endpoint can launch 'SafeZone' (also called Avastium), a Chromium fork with critical security checks removed.. URL: https://bugs.chromium.org/p/project-zero/issues/detail?id=679
[CSRF-EXPLOIT-KIT]
Kafeine. An Exploit Kit dedicated to CSRF Pharming. URL: http://malware.dontneedcoffee.com/2015/05/an-exploit-kit-dedicated-to-csrf.html
[DRIVE-BY-PHARMING]
Sid Stamm; Zulfikar Ramzan; Markus Jakobsson. Drive-By Pharming. URL: https://link.springer.com/chapter/10.1007/978-3-540-77048-0_38
[IPV4-REGISTRY]
IANA IPv4 Special-Purpose Address Registry. URL: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
[IPV6-REGISTRY]
IANA IPv6 Special-Purpose Address Registry. URL: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
B. Carpenter; S. Cheshire; R. Hinden. Representing IPv6 Zone Identifiers in Address Literals and Uniform Resource Identifiers. 2023년 4월 12일. Internet-Draft. URL: https://www.ietf.org/archive/id/draft-ietf-6man-rfc6874bis-07.html
[MIXED-CONTENT-2]
Emily Stark; Mike West; Carlos Ibarra Lopez. Mixed Content Level 2. 2020년 10월 14일. W3C First Public Working Draft. URL: https://w3c.github.io/webappsec-mixed-content/level2.html
[PLEX]
Filippo Valsorda. How Plex is doing HTTPS for all its users. URL: https://blog.filippo.io/how-plex-is-doing-https-for-all-its-users/
[RFC1122]
R. Braden, Ed.. Requirements for Internet Hosts - Communication Layers. 1989년 10월. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc1122
[RFC1918]
Y. Rekhter; et al. Address Allocation for Private Internets. 1996년 2월. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc1918
[RFC2544]
S. Bradner; J. McQuaid. Benchmarking Methodology for Network Interconnect Devices. 1999년 3월. Informational. URL: https://www.rfc-editor.org/rfc/rfc2544
[RFC3927]
S. Cheshire; B. Aboba; E. Guttman. Dynamic Configuration of IPv4 Link-Local Addresses. 2005년 5월. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc3927
[RFC4193]
R. Hinden; B. Haberman. Unique Local IPv6 Unicast Addresses. 2005년 10월. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc4193
[RFC4291]
R. Hinden; S. Deering. IP Version 6 Addressing Architecture. 2006년 2월. Draft Standard. URL: https://www.rfc-editor.org/rfc/rfc4291
[RFC6555]
D. Wing; A. Yourtchenko. Happy Eyeballs: Success with Dual-Stack Hosts. 2012년 4월. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc6555
[RFC6598]
J. Weil; et al. IANA-Reserved IPv4 Prefix for Shared Address Space. 2012년 4월. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc6598
[RFC6762]
S. Cheshire; M. Krochmal. Multicast DNS. 2013년 2월. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc6762
[RFC8305]
D. Schinazi; T. Pauly. Happy Eyeballs Version 2: Better Connectivity Using Concurrency. 2017년 12월. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc8305
[SECURE-LOCAL-COMMUNICATION]
Minutes from 'Secure communication with local network devices': TPAC, 2015. URL: http://www.w3.org/2015/10/28-local-minutes.html
[SOHO-PHARMING]
Team Cymru. SOHO Pharming. URL: https://331.cybersec.fun/TeamCymruSOHOPharming.pdf
[TREND-MICRO]
TrendMicro node.js HTTP server listening on localhost can execute commands. URL: https://bugs.chromium.org/p/project-zero/issues/detail?id=693

IDL 색인

enum IPAddressSpace { "public", "private", "local" };

dictionary PrivateNetworkAccessPermissionDescriptor
    : PermissionDescriptor {
  DOMString id;
};

partial dictionary RequestInit {
  IPAddressSpace targetAddressSpace;
};

partial interface Request {
  readonly attribute IPAddressSpace targetAddressSpace;
};

이슈 색인

이 주소들에 대한 접근이 완전히 차단되면 IPv4 매핑 IPv6 주소에 대한 특별 사례를 제거한다. [Issue #36]
private network requests의 정의는 current urlhostIP address spacepublic이 아닌 IP 주소에 매핑되는 모든 교차 출처 요청을 포함하도록 확장될 수 있다. 이는 프라이빗 네트워크의 악의적 서버가 다른 서버를 공격하지 못하게 할 것이다. 이러한 변경을 출시하는 데 필요한 노력은 현재로서는 보상에 비해 가치가 없다고 판단된다. 이는 나중에 점진적 개선으로 출시할 수 있다. [Issue #39]
원격 엔드포인트 개념은 아직 [FETCH]에 명시되어 있지 않으므로, 이는 어느 정도 손짓 설명에 머무른다. [Issue #33]
WebSocket 핸드셰이크는 <img> 태그와 대략 같은 기능을 가지므로, 프리플라이트 요청은 WebSocket 핸드셰이크에 앞서 전송되는 것이 좋을 것이다. WebSocket 연결 수립Fetch 알고리즘에 의존한다는 점을 고려하면, 이를 명시하는 데 추가 작업이 필요하지 않을 수도 있다. [Issue #14]
Service Worker soft update 알고리즘은 업데이트된 스크립트를 fetching할 때 유감스럽게도 request client"null"로 설정한다. 이는 온갖 문제를 일으키며, 위에 제시된 private network access check 알고리즘을 방해한다. 실제로 fetch 중에 policy container를 복사해 올 request client가 없다. [Issue #83]
구현 경험 이후 이를 재평가한다.
여기서 Chromium의 동작을 명시하고 설명한다. [Issue #75]
일부 소비자용 라우터는 DNS 리바인딩 공격에 대해 과도하게 공격적인 보호를 구현하여, non-public IP 주소로 확인되는 DNS 응답을 단순히 차단한다. 이는 [PLEX]와 같은 해결책에 걸림돌이 된다. 우회 방법은 링크된 이슈에서 논의된다. [Issue #23]
가능한 완화책은 네트워크 변경을 감지하고 이전 네트워크에 특정한 상태를 지우는 것을 요구할 것이다. 이를 완전히 일반적인 방식으로 수행하는 것은 모든 상태를 지우는 것 외에는 불가능할 가능성이 높다. 어쩌면 실용적인 절충점에 도달할 수 있을 것이다. [Issue #28]
다음 내용은 더 이상 정확하지 않다. 구현 경험은 캐시와의 통합이 CSRF 공격으로부터 네트워크 리소스를 보호하는 데에도 유용하다는 점을 드러냈다. 이 절은 다시 작성되어야 한다. [Issue #75]