1. 소개
이 절은 규범적이지 않다.
콘텐츠 보안 정책은 교차 사이트 스크립팅 공격에 대한 훌륭한 방어 수단으로, 개발자가
악성 스크립트, 스타일 및 기타 리소스 유형의 삽입에 대해 자신의 사이트를 강화할 수 있게 한다.
그러나 이는 개발자에게
iframe을
통해 로드된
제3자 콘텐츠에 제한을 적용할 수 있는 능력을 제공하지는 않는다.
CSP를 이러한 제3자 컨텍스트에 직접 적용하도록 허용하는 것은 위험할 수 있다. CSP는 리소스 로딩에 대해
상당히 세분화된 제어를 제공하며, 특정 스크립트에 대한 접근을 거부함으로써 원래는 안전한 페이지에
취약점을 도입할 가능성이 매우 높다. 우리는 과거의
X-XSS-Protection과 같은 기능에서 이러한 종류의 문제를 보았으므로,
이를 새로운 형태로 다시 도입하지 않도록 주의해야 한다.
그렇지만 위젯, 광고 및 기타 종류의 제3자 콘텐츠에 제한을 둘 수 있다면 매우 유용할 것이다. 이 문서는 임베드된 콘텐츠의 명시적 옵트인에 의존하는 메커니즘을 제안하며, 이는 위젯이 임베더와 협력하여 합리적인 제한 집합을 협상할 수 있게 할 것이다.
요약하면, 임베더는
iframe
요소에 속성을 설정하여 콘텐츠 보안 정책을 제안한다. 이 정책은 프레임된 콘텐츠에 대한 HTTP 요청과 함께 HTTP
요청 헤더
(`Sec-Required-CSP`)로
전송된다.
임베드된 콘텐츠가 해당 정책을 수락할 수 있다면,
응답과 함께
`Content-Security-Policy`
또는
`Allow-CSP-From`
헤더를 반환하여 이를
시행할 수 있다.
응답에 임베더가 요청한 정책만큼 엄격한 정책이 포함되어 있거나, 임베더가 제공한 정책을 수락한다면 사용자 에이전트는 임베드된 콘텐츠를 렌더링한다. 그러한 단언이 없으면 응답은 차단된다.
1.1. 예제
iframe
요소를 통해 포함하고
csp
속성을 사용함으로써 이를 수행할 수 있다:
<iframe src="https://advertisements-r-us.example.com/ad1.cfm"
csp="script-src https://trusted-cdn.example.com/">
</iframe>
이는 다음과 같이
`Sec-Required-CSP`
헤더가 있는 advertisements-r-us.example.com에 대한 요청을 생성한다:
GET / HTTP/1.1 Host: advertisements-r-us.example.com ... Sec-Required-CSP: script-src https://trusted-cdn.example.com/ ...
광고 서버는 이 요청 헤더를 파싱하고, 이를 수락할 수 있다고 판단한 뒤,
임베더(https://example.com)가 부과한 제한을 준수하겠다고 사용자 에이전트에 알리는
헤더를 응답에 추가한다:
HTTP/1.1 200 OK ... Allow-CSP-From: https://example.com
Content-Security-Policy`
헤더를 내보내어 제한을 수락할 수도 있다. 예를 들어, 임베더가 허용하는 것과 관계없이
플러그인이 로드되지 않도록 보장하고 싶을 수 있다. 서버는 임베더의 제한을 포함하고
그 위에 더 많은 제한을 추가하는 정책을 내보냄으로써 이를 수행할 수 있다:
HTTP/1.1 200 OK ... Content-Security-Policy: script-src https://trusted-cdn.example.com/; object-src 'none'
응답이 단언한 정책이 요청이 요구한 정책보다 엄격하게 더 적은 요청만 허용하므로, 프레임은 성공적으로 로드된다.
서버는 두 개의 정책, 즉 임베더의 제한을 정확히 반영하는 정책 하나와 이를 더 강화하는 또 다른 정책을 전달할 수도 있다:
HTTP/1.1 200 OK ... Content-Security-Policy: script-src https://trusted-cdn.example.com/, object-src 'none'
`Content-Security-Policy`
헤더 값의 ","는 문자열을 두 개의
직렬화된 정책으로 분할하며, 각각이 시행된다. 사용자 에이전트는 응답과 함께 전달된 정책 중
하나가 요구사항과 일치하는지 검증하고, 추가 정책은 페이지의 유효 정책을 더
제한적으로 만들 수밖에 없으므로 프레임이 성공적으로 로드되도록 허용한다.
2. 프레임워크
높은 수준에서, 이 문서는 임베디가 임베더가 지정한 제한 집합에 옵트인할 수 있게 하는 메커니즘을 설명한다. 이 메커니즘은 몇 가지 단계를 포함한다:
-
임베더는
csp속성을iframe요소에 사용하여 필수 정책을 지정한다. 이는 § 2.1 <iframe>의 csp 속성에서 더 자세히 설명한다. -
해당 속성의 값은 `
Sec-Required-CSP` 요청 헤더로 함께 전송되며,iframe의 자식 navigable을 대상으로 하는 모든 navigation request에 포함된다. 이 헤더는 § 2.2 Sec-Required-CSP HTTP 요청 헤더에서 더 자세히 설명한다. -
서버는 `
Sec-Required-CSP` 헤더를 검사하여 필수 정책을 수락할 것인지 결정할 수 있다. 수락하려는 경우, 필수 정책만큼 강력한 정책을 포함하는 `Content-Security-Policy` 헤더를 응답에 전송하여 암시적으로 옵트인하거나, 임베딩 출처가 원하는 어떤 정책이든 설정할 수 있게 하는 `Allow-CSP-From` 헤더를 응답에 전송하여 명시적으로 옵트인할 수 있다. 명시적 메커니즘은 간단하며 § 2.3 Allow-CSP-From HTTP 응답 헤더에서 설명한다. 암시적 메커니즘은 꽤 복잡하며, § 3 암시적 정책 수락 절 전체를 구성한다.서버가 필수 정책을 수락하고 싶지 않다면 명시적 오류를 반환하거나, 일치하는 `
Content-Security-Policy` 헤더나 `Allow-CSP-From` 헤더 없이 일반 데이터를 그대로 반환할 수 있다. 이 경우 사용자 에이전트는 응답을 차단한다. HTML의 navigate 알고리즘과의 통합은 § 2.4 HTML과의 통합에서 설명되며, 차단 메커니즘은 § 4.1 request에 대한 response가 requiredCSP에 의해 차단되는가?에 자세히 명시되어 있다.
2.1. <iframe>의 csp 속성
iframe
요소는 임베드된 문서가 스스로 시행하기로 동의해야 하는 정책을 지정하는
csp 속성을 가진다. 예를 들어, 다음
HTML은 https://embedee.example.com/을 로드하고,
object-src 'none'이 그 문서에 대해 시행되도록 보장한다:
<iframe src="https://embedee.example.com/" csp="object-src 'none'"> </iframe>
문자열
(value)은 다음 모든 문장이 참인 경우, 주어진
요소 (element)의
csp
속성에 대한
유효한 속성 값이다:
-
value가 빈 문자열이 아니다.
-
value의 길이가 4096 이하이다.
참고: 서버를 잠재적으로 혼란스러운 입력으로부터 보호하기 위해
csp속성 값에 최대 길이를 적용한다. 아래 § 5.4 헤더 길이를 보라. -
value가 [CSP]에 정의된 serialized-policy ABNF 문법과 일치한다.
-
다음 문장 중 하나가 참이다:
-
element의 node document의 policy container의 required CSP가
null이다. -
value를 "
enforce"로 파싱한 결과가 element의 node document의 policy container의 required CSP에 의해 포섭된다.
-
-
value를 "
enforce"로 파싱한 결과가 다음 지시문 중 어떤 것도 포함하지 않는 directive set을 가진다:
csp
속성의 유효한 값이다:
-
script-src 'none' -
script-src 'self'; object-src 'none'; sandbox -
not-a-directive https://whatever.not-a-tld
참고: 마지막 항목은 의미 있는 정책을 표현하지 않더라도, 향후 CSP 구문과의 전방 호환성을 유지하기 위해 유효한 것으로 간주한다.
반면 다음은 CSP 구문과 일치하지 않으므로, 유효한 속성 값으로 간주되지 않는다:
-
script-src *\nInjected-Header: XSS! -
💩
참고:
csp
속성에 허용하는 값에 주의해야 한다. 그 내용은 결국 HTTP 요청 헤더로 반사되기 때문이다.
이 우려는 에서 조금 더 자세히 논의한다.
iframe의
csp
속성에는 다음 WebIDL 문법
[WEBIDL]로 정의되는 대응 IDL 속성이
있다:
partial interface HTMLIFrameElement { [CEReactions ]attribute DOMString ; };csp
csp
IDL 속성은 요소의
csp
속성을
반영해야 한다.
2.2. Sec-Required-CSP HTTP 요청 헤더
임베드된 리소스가 임베더의 요구사항을 준수할 의사가 있는지 여부를 결정할 수 있도록 하기 위해,
iframe의
csp
속성에 표현된 정책은
"Sec-Required-CSP" HTTP 요청 헤더를 통해 영향을 받는
navigation
request와 함께 전달된다. 헤더의 값은 다음 ABNF
[RFC5234]로 표현된다:
Sec-Required-CSP = serialized-policy
사용자 에이전트는
"Sec-Required-CSP"라는 이름의 HTTP 응답 헤더 필드를 하나보다 많이 보내서는 안 되며,
그러한 헤더는 하나보다 많은
serialized-policy를 포함해서는 안 된다.
서버는 수신한 첫 번째 해당 헤더의 첫 번째 정책만 처리해야 한다.
에서 논의하듯, 서버는 정책을 클라이언트에 단순히
반사하는 것의 영향을 신중히 고려해야 한다. 서버가 임베더의 요구사항을 단순히
수락하려는 경우,
`Allow-CSP-From`
헤더가 더 안전한 선택이다.
이 헤더는 HTML의 navigate 알고리즘의 일부로 설정된다(다음 알고리즘을 호출하는 훅에 대한 자세한 내용은 § 2.4 HTML과의 통합을 보라):
Sec-Required-CSP
헤더를 설정하려면, 다음 단계를 실행한다:
-
request가 navigation request가 아니면 반환한다.
-
requirement가
null이면 반환한다. -
Assert: requirement는 [CSP]에 정의된 serialized-policy 문법과 일치하는 serialized CSP이다.
-
request의 header list에 "`
Sec-Required-CSP`"라는 이름과 requirement 값을 가진 헤더를 추가한다.
2.3.
Allow-CSP-From HTTP 응답 헤더
임베디는
"Allow-CSP-From" HTTP 응답 헤더로 응답함으로써
임베더가 지정한 정책을 수락하는 데 옵트인할 수 있다. 헤더의 값은 다음 ABNF
[RFC5234]로 표현된다:
Allow-CSP-From = origin-or-null / wildcard
2.4. HTML과의 통합
-
iframe요소는 § 2.1 <iframe>의 csp 속성에서 정의된csp속성을 가진다. -
policy container struct에 required CSP 항목을 추가한다. 이는 serialized CSP 또는 null이며, 처음에는 null이다.
-
target snapshot params struct에 required CSP 항목을 추가한다. 이는 serialized CSP 또는 null이다.
-
HTML의 snapshotting target snapshot params 알고리즘을 갱신하여 새 required CSP 항목을 targetNavigable이 주어졌을 때 determine the required CSP의 결과로 설정한다.
-
navigation params struct에 required CSP 항목을 추가한다. 이는 serialized CSP 또는 null이다.
-
navigate 알고리즘을 갱신하여, 18.7.7단계에서 생성된 navigation params struct의 required CSP를 targetSnapshotParams의 required CSP로 설정한다.
-
HTML의 create navigation params by fetching 알고리즘에서 request가 생성된 뒤 다음 단계를 추가한다:
-
request와 targetSnapshotParams의 required CSP에 대해 set the Sec-Required-CSP header를 실행한다.
-
-
반환되는 navigation params의 required CSP를 targetSnapshotParams의 required CSP로 설정하도록 create navigation params by fetching을 갱신한다.
-
반환되는 navigation params의 required CSP를 targetSnapshotParams의 required CSP로 설정하도록 create navigation params from a srcdoc resource를 갱신한다.
-
HTML의 creating a policy container from a fetch response 알고리즘에 선택적 requiredCSP (null을 기본값으로 하는 serialized CSP 또는 null) 인수를 추가하고, 다음 단계를 추가한다:
-
requiredCSP가 null이 아니면:
-
required policy를 requiredCSP를 "
enforce"로 파싱한 결과로 둔다. -
response policies를 response의 Content Security Policies를 파싱한 결과로 둔다.
-
required policy, response의 url의 origin, response policies, 그리고 response의 url의 origin에 대해 실행했을 때 § 3.2.1 CSP 목록 포섭이 "
Does Not Subsume"를 반환하면:참고: 응답의 정책이 이미 필수 정책을 포섭한다면, 필수 정책을 policy container에 추가하지 않는다. 이는 임베더가 특정 nonce(예:
nonce-abc)를 요구하고, 임베디가 자체 호환 nonce(예:nonce-xyz)를 제공하는 경우, 사용자 에이전트가 임베디의 nonce만 시행하도록 보장한다. 둘 다 추가한다면, 어떤 스크립트도 두 nonce를 동시에 만족할 수 없으므로 문서는 사실상 모든 스크립트를 차단하게 된다. -
result의 required CSP를 requiredCSP로 설정한다.
-
-
-
targetSnapshotParams의 required CSP를 creating a policy container from a fetch response에 전달하도록 create navigation params by fetching을 갱신한다.
-
HTML의 navigate 알고리즘에서 탐색을 차단하게 하는 조건 목록에 다음을 추가한다(예:
X-Frame-Options검사 뒤):-
navigationParams의 response,navigationParams의 request, 그리고navigationParams의 required CSP에 대해 실행했을 때 § 4.1 request에 대한 response가 requiredCSP에 의해 차단되는가? 알고리즘이 "Blocked"를 반환한다.
-
2.4.1. 필수 CSP
-
navigable이 child navigable이 아니면
null을 반환한다. -
navigable의 container가 유효한 속성 값 (value)을 가진
csp속성을 가지고 있으면, value를 반환한다. -
navigable의 container document의 policy container의 required CSP를 반환한다.
3. 암시적 정책 수락
임베디는 응답과 함께
`Allow-CSP-From`
헤더를 반환함으로써 임베더가 지정한 정책 요구사항을 명시적으로 수락할 수 있다. 또한 요구사항은
임베더가 요구한 정책만큼 엄격한 순효과를 가지는 정책(또는 정책 집합)을 포함하는
`Content-Security-Policy`
헤더를 전달함으로써 암시적으로 수락될 수도 있다.
그러나 "최소한 그만큼 엄격하다"는 표현은 그다지 정밀하지 않다. 단순한 경우는 명확하다. 예를 들어
임베더가 object-src https://cdn.example.com을 요구하면, 임베디는
object-src 'none'으로 응답할 수 있다. 전자에 의해 차단될 모든 가능한 리소스는
후자에 의해서도 차단되므로(객체를 전혀 허용하지 않기 때문에), 임베딩을 차단하지 않는다. CSP의
구문적 복잡성은 더 복잡한 경우를 추론하기 다소 어렵게 만든다. 예를 들어
script-src 'unsafe-inline' http: 'sha256-abc...def'가 주어지면,
script-src 'unsafe-inline'이 요구된 정책의 부분집합처럼 보일 수 있다. 그러나
hash-source 표현식이 존재한다는 것은
요구된 정책에서 'unsafe-inline'이 무시된다는 뜻이므로, 겉보기와 달리
후자의 정책은 실제로 전자보다 더 많은 것을 허용하게 된다.
여기서는 "최소한 그만큼 엄격하다"라는 개념을 "포섭"이라고 부른다. 하나의 content security policy object (A)는 B가 허용하는 모든 것을 A도 허용하는 경우 다른 객체 (B)를 포섭한다고 한다. 이 경우 A는 B를 포섭하거나, B는 A에 의해 포섭된다.
하지만 항상 단일 정책만 비교하는 것은 아니다. 여러 정책이 CSP list에 존재하는 경우, 이들은 "The effect of multiple policies"에 설명된 결합된 효과를 가진다. 여기서는 CSP list의 결합된 효과를 그들의 교집합이라고 한다. 자세한 내용은 아래 § 3.1 교집합에 명시되어 있다.
교집합이 정의되면, A가 포섭하는 CSP list라는 것은 A가 그 목록의 교집합을 포섭하는 경우에만 성립한다고 말할 수 있다.
3.1. 교집합
3.1.1. CSP 목록 교집합
origin (origin)에 대한 CSP list (list)의 교집합은 이들의 순효과를 나타내는 단일 Content Security Policy object이며, 다음 알고리즘으로 생성된다:
참고: 여러 정책의
교집합을 항상 단일
정책으로 표현할 수 있는 것은 아니다.
예를 들어 script-src 'unsafe-inline'과
script-src 'nonce-abc'를 생각해 보라.
전자는 인라인 스크립트만 허용하고, 후자는 특정 토큰이 있는 인라인 또는 외부화된 스크립트만
허용한다. 순효과(특정 토큰이 있는 인라인 스크립트만 허용)는 단일 정책으로 만들 수 없다.
이러한 정책을 다루는 일은 현재로서는 독자의 연습 문제로 남겨둔다.
독자에게 이 연습을 시켜서는 안 된다. 또한 단일 정책으로 표현할 수 없는 교집합을 처리하는 방법에 대한 지침도 제공해야 한다(예: 정책 목록을 유지하는 방식).
-
result를 빈 directive set과 "
enforce"인 disposition을 가진 content security policy object로 둔다. -
list의 각 policy에 대해:
-
policy의 disposition이 "
report"이면, 계속한다. -
result를 origin에 대한 result와 policy의 교집합으로 설정한다.
-
-
result를 반환한다.
«
"default-src 'self' http://example.com http://example.net; connect-src 'none';",
"connect-src http://example.com/; script-src http://example.com/",
"style-src 'self'; script-src http://example.com/ http://example.net",
»
다음 serialized CSP를 파싱하여 생성된 정책이다:
"default-src 'self' http://example.com http://example.net; connect-src 'none'; script-src http://example.com/; style-src 'self'"
초기 목록에 지정된 각 정책은 그 교집합을 포섭한다.
3.1.2. 정책 교집합
origin (origin)에 대한 두 Content Security Policy objects (A와 B)의 교집합은 이들의 결합된 효과를 나타내는 단일 Content Security Policy object이며, 다음 알고리즘으로 생성된다:
-
Assert: A와 B는 모두 "
enforce"인 disposition을 가진다. -
A의 directive set이 비어 있으면, B를 반환한다.
-
B의 directive set이 비어 있으면, A를 반환한다.
-
policy를 빈 directive set과 "
enforce"인 disposition을 가진 새 content security policy object로 둔다. -
directive names를 빈 set으로 둔다.
-
A의 각 directive에 대해:
-
B의 각 directive에 대해:
-
directive names의 각 directive name에 대해:
-
directive name이 "
report-uri", "report-to"이면, 계속한다. -
directive A를 directive name과 A에 대한 유효 지시문 값으로 둔다.
-
directive B를 directive name과 B에 대한 유효 지시문 값으로 둔다.
-
Assert: directive A와 directive B가 모두
null은 아니며, 둘의 values가 모두 source lists이거나, 둘의 values가 모두 source lists가 아니다. -
directive A 또는 directive B 중 하나라도 value가 source list가 아니면, 계속한다.
source list가 아닌 것들을 처리하도록 이 정의를 확장해야 한다. 또한 이에 대해 더 정밀해야 하며, 아마도 directive name에 대해 검사할 수 있는 "source list directive" 같은 용어를 정의해야 할 것이다.
-
directive A가
null이면: -
directive B가
null이면: -
directive value를 directive A의 value, directive B의 value, directive name, 그리고 origin의 교집합으로 둔다.
-
directive를 다음 속성을 가진 새 directive로 둔다:
-
directive를 policy의 directive set에 추가한다.
-
-
policy를 반환한다.
"default-src 'self' http://example.com http://example.net; connect-src 'none';" and "connect-src http://example.com/; script-src http://example.com/"
다음 serialized CSP를 파싱하여 얻은 정책이다:
"default-src 'self' http://example.com http://example.net; connect-src 'none'; script-src http://example.com/;"
주어진 두 정책은 모두
교집합을
포섭한다.
예를 들어,
그
교집합의
"script-src http://example.com/"은 첫 번째 정책의
"default-src 'self' http://example.com http://example.net"와 두 번째 정책의
"script-src http://example.com/"에 의해
포섭된다.
3.1.3. 소스 목록 교집합
directive name (name)과
origin (origin)에 대한 두
source lists의
교집합은 이들의 순효과를 나타내는
source list이다.
그러한
source list가
존재하지 않는 경우(예:
A의 https://example.com/와
B의 https://not-example.com), 교집합은
목록 « 'none' »가 된다.
-
effective A를 A, name, origin에 대한 유효 소스 목록으로 둔다.
-
effective B를 B, name, origin에 대한 유효 소스 목록으로 둔다.
-
effective A 또는 effective B 중 하나라도 «
'none'»이면, «'none'»를 반환한다. -
effective A가 비어 있으면, effective B를 반환한다.
-
effective B가 비어 있으면, effective A를 반환한다.
-
schemes를 빈 set으로 둔다.
-
intersection을 빈 source list로 둔다.
-
effective B의 각 expression B에 대해:
-
expression B가
scheme-source문법과 일치하고 effective A에 포함되어 있으면, expression B를 schemes에 추가한다.참고: 위에서 유효 소스 목록을 얻었다는 것은
scheme-source문법과 일치하는 토큰이 이미 정규화되어 "http:"/"ws:"가 "https:"/"ws:" 없이 나타나는 일이 없다는 뜻이다.
-
-
schemes의 각 expression에 대해:
-
effective A의 각 expression A에 대해:
-
expression A가
scheme-source문법과 일치하고 schemes가 expression A를 포함하면, 계속한다. -
effective B의 각 expression B에 대해:
-
expression A와 expression B 중 적어도 하나가
scheme-source또는host-source문법과 일치하지 않으면:-
expression A가
keyword-source문법과 일치하고 expression B와 ASCII 대소문자 구분 없음으로 일치하면, expression A를 intersection에 추가한다. -
expression A가
nonce-source또는hash-source문법과 일치하고 expression B와 같으면, expression A를 intersection에 추가한다. -
다음 expression B로 계속한다.
-
-
expression B의
scheme-part가 schemes의 요소 중 하나와 일치하면, 다음 expression B로 계속한다. -
expression A와 expression B의 교집합이
null이 아니면, 그 결과를 intersection에 추가한다.
-
-
-
intersection을 반환한다.
intersection은 A와 B에 대한
교집합이다.
A = wss: http://example.com B = https: wss: 'none' intersection = wss: https://example.com
표현식 "wss:"는 두 정책 모두에 있으므로, 그들의 교집합에도 존재한다. 마찬가지로, "http://example.com"은 "http://example.com"과 "https:" 모두에 의해 포섭되는 유일한 표현식이므로 교집합에 존재한다. "'none'""은 B의 유일한 토큰이 아니므로 무시된다는 점에 주의하라.
A = http://sub.a.com http://*.b.com B = https://sub.a.com:* http://*.c.com intersection = https://sub.a.com
유사한 소스는 두 개뿐이다. A의 "http://sub.a.com"은 B의 "https://sub.a.com:*"와 유사하므로 두 소스 목록의 교집합은 "https://sub.a.com"이다.
A = 'unsafe-inline' http://example.com:443/page1/html 'nonce-abc' B = 'unsafe-inline' https://example.com:443/ 'strict-dynamic' 'nonce-abc' intersection = 'nonce-abc'
"strict-dynamic"은
nonce-source와
hash-source 표현식만 인정하므로,
B는 사실상 "'strict-dynamic' 'nonce-abc'"이다.
따라서 교집합은 "'nonce-abc'"이다.
3.1.4. 소스 표현식 교집합
source expression은
scheme-source 또는 host-source 문법과 일치하는 다른 두 표현식
A와 B의 더 제한적인
scheme-part,
host-part, port-part, 그리고 path-part를 포함하는 경우 그 두 표현식의
교집합이라고 한다.
Intersect는 A와 B의
교집합이다.
A = https: B = http: Intersect = https: //http:allows bothhttp:andhttps:, sohttps:is the intersection.
A = http://*.example.com B = https://sub.example.com:* Intersect = https://sub.example.com:443 // A does not specify a port, so only default ports are allowed.
A = http://example.com:80/page1/html
B = https://example.com:443/
Intersect = null
// A is explicitly locked to port 80, which cannot match B's equally explicit port 443.
A = https:
B = http://example.com
Intersect = https://example.com.
A = https://sub.example.com:*
B = http://*.example.com/page.html
Intersect = https://sub.example.com/page.html
3.1.4.1. scheme-source와
host-source 교집합
scheme-source 또는
host-source 문법과 일치하는 두
source expressions (A와
B)가 주어졌을 때,
A가 B와
source-expression similar이면 그들의
교집합을 반환한다. 그렇지 않으면
null을 반환한다.
-
A가 B와 source-expression similar하지 않으면,
null을 반환한다. -
source를 빈 문자열로 둔다.
-
scheme A를 A의
scheme-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
scheme B를 B의
scheme-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
more secure scheme B를 scheme A가 scheme B와
scheme-partmatch하지 않으면true로, 그렇지 않으면false로 둔다. -
scheme A가
null이 아니고 more secure scheme B가false이면 scheme A와 ":"를 source에 추가한다. 그렇지 않고 scheme B가null이 아니면 scheme B와 ":"를 source에 추가한다. -
A와 B가 모두
scheme-source문법과 일치하면, source를 반환한다. -
source가 비어 있지 않으면 "//"를 source에 추가한다.
-
host A를 A의
host-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
host B를 B의
host-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
host A가
null이 아니면:-
host B가
null이면, host A를 source에 추가한다. 주 알고리즘의 다음 단계로 계속한다. -
A가
scheme-source문법과 일치하지 않고 wildcard host를 가지지 않으면, host A를 source에 추가한다. -
그렇지 않으면, host B를 source에 추가한다.
-
-
host A가
null이면, host B를 source에 추가한다. -
port A를 A의
port-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
port B를 B의
port-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
port A가
null이면, port B가null이 아닌 경우 ":"와 port B를 source에 추가한다. -
port A가
null이 아니면:-
port B가
null이면, ":"와 port A를 source에 추가한다. 주 알고리즘의 다음 단계로 계속한다. -
A가 wildcard port를 가지지 않고 more secure scheme B가
false이면, ":"와 port A를 source에 추가한다. -
그렇지 않으면, ":"와 port B를 source에 추가한다.
-
-
path A를 A의
path-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
path B를 B의
path-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
path A가
null이면, path B가null이 아닌 경우 path B를 source에 추가한다. -
path A가
null이 아니면:-
path B가
null이면, path A를 source에 추가한 결과를 반환한다. -
path A가 path B와
path-partmatches하면, path A를 source에 추가한다. -
그렇지 않으면, path B를 source에 추가한다.
-
-
source를 반환한다.
3.1.5. 교집합 헬퍼
3.1.5.1. 유효 지시문 값
-
name에 대해 전환하고 관련 단계를 실행한다:
- "
child-src"- "
connect-src"- "
font-src"- "
img-src"- "
manifest-src"- "
media-src"- "
object-src"- "
script-src"- "
style-src" - "
- "
script-src-elem"- "
script-src-attr" - "
- "
style-src-elem"- "
style-src-attr" - "
- "
frame-src" - "
worker-src" - "
base-uri"- "
block-all-mixed-content"- "
default-src"- "
frame-ancestors"- "
form-action"- "
plugin-types"- "
report-uri"- "
require-sri-for"- "
sandbox"- "
upgrade-insecure-requests" - "
- "
-
null을 반환한다.
3.1.5.2. 유효 소스 목록
'self'와 * 같은 복잡한 토큰을 확장하고, 효과가 없거나, 무효화되었거나, 유효하지 않은
토큰(예를 들어 nonce가 있는 경우의 'unsafe-inline')을 제거하는
list의 단순화이다. 다음 단계를 실행한 결과는 일반적으로 list보다 더 길지만,
비교하기는 훨씬 더 간단하다:
-
list가 비어 있거나 « 'none' »이면, « 'none' »을 반환한다.
-
result를 빈 source list로 둔다.
-
list의 각 expression에 대해:
-
expression이 "
'self'"이면:-
origin이 주어졌을 때 § 4.2.1 'self'를 origin에 대한 host-source 표현식으로 다시 쓰기.를 실행한 결과를 result에 추가한다.
-
계속한다.
-
-
expression이
keyword-source문법과 일치하고, name이 "script-src" 또는 "style-src"가 아니면, 계속한다. -
다음 문장 중 하나라도 참이면 계속한다:
-
expression이 "
'none'"이다 -
expression이 "
'strict-dynamic'"이고 name이 "script-src"가 아니다 -
expression이
nonce-source또는hash-source문법 중 하나와 일치하고, name이 "script-src" 또는 "style-src"가 아니다 -
expression이 "
'unsafe-inline'"이고, name이 "script-src이며, 그리고 list가 다음 중 하나와 일치하는 토큰을 하나 이상 포함한다:nonce-source문법,hash-source문법, 또는 "'strict-dynamic'" -
expression이
host-source또는scheme-source문법 중 하나와 일치하고, name이 "script-src"이며, amd list가 "'strict-dynamic'" 토큰을 포함한다 -
name이 "
plugin-types"이고, expression이serialized-source-list문법과 일치하지 않는다
-
-
expression이 U+002A ASTERISK 문자(
*)이면: -
expression이 scheme-source 문법과 일치하면:
-
expression이 host-source 문법과 일치하면:
-
expression의 scheme-part가 "http"이면, "https://", expression의 host-part, expression의 port-part, 그리고 expression의 path-part를 연결한 결과를 result에 추가한다.
-
expression의 scheme-part가 "ws"이면, "wss://", expression의 host-part, expression의 port-part, 그리고 expression의 path-part를 result에 연결한 결과를 추가한다.
-
-
expression을 result에 추가한다.
-
-
result가 비어 있거나 « 'strict-dynamic' »이면, « 'none' »을 반환한다.
-
result를 반환한다.
origin이 https://example.test/인 임의의 지시문에 대해:
https: wss: 'none' 'self'유효 소스 목록은 "http: wss: https://example.test/"이다. "'none'"은 유일한 소스가 아닐 때 아무 효과가 없으므로 유효 소스 목록의 일부가 아니라는 점에 유의하라.
"style-src"에 대해:
http://example.com 'strict-dynamic' 'nonce-abc'유효 소스 목록은 "http://example.com 'nonce-abc'"이다. "'strict-dynamic'"은 "
script-src"가 아닌 지시문에서는 무시되기 때문이다.
"script-src"에 대해:
http://example.com 'strict-dynamic' 'nonce-abc'유효 소스 목록은 "'strict-dynamic' 'nonce-abc'"이다. "
script-src"의 경우
"'strict-dynamic'"은 host 및 scheme 소스 표현식을 인정하지 않기 때문이다.
3.1.5.3. 소스 표현식 유사성
source expression (A)은 A가
B와
같거나,
또는 문법의 관련 부분이 일치하는 경우(예를 들어 scheme-source 표현식의 경우,
각각의 scheme-part가 어느 한 방향으로
scheme-part match해야 한다),
다른
source expression (B)과
source-expression
similar하다고 한다.
참고: 이 속성은 대칭적이다. 즉 A가 B와 source-expression similar하면, B 역시 A와 source-expression similar하다.
source expression의 host-part의 첫 번째
문자가 U+002A ASTERISK 문자(*)인 경우, 그
source expression은
wildcard host를 가진다.
source expression의 port-part가 U+002A ASTERISK 문자(*)인
경우, 그 source
expression은
wildcard port를 가진다.
-
A의 문법이 B의 문법과 일치하지 않으면, "
Not Similar"를 반환한다. -
A가
keyword-source,nonce-source, 또는hash-source문법과 일치하면:-
A가 B와 같으면, "
Similar"를 반환한다. -
"
Not Similar"를 반환한다.
-
-
scheme A를 A의
scheme-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
scheme B를 B의
scheme-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
scheme A가 scheme B와 scheme-part match하지 않고, scheme B도 scheme A와 scheme-part match하지 않으면, "
Not Similar"를 반환한다. -
A 또는 B가
scheme-source문법과 일치하면, "Similar"를 반환한다. -
host A를 A의
host-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
host B를 B의
host-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
port A를 A의
port-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
port B를 B의
port-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
path A를 A의
path-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
path B를 B의
path-part(존재하는 경우)로, 그렇지 않으면null로 둔다. -
다음 중 하나라도 참이면 "
Not Similar"를 반환한다:-
A와 B가 모두 wildcard host를 가지지만, host A가 host B와 ASCII 대소문자 구분 없음으로 일치하지 않는다.
-
A와 B 중 최대 하나만 wildcard host를 가지고, host A가 host B와
host-partmatch하지 않으며, host B도 host A와host-partmatch하지 않는다. -
A와 B 모두 wildcard port를 가지지 않고, port A가 port B와
port-partmatch하지 않으며, port B도 port A와port-partmatch하지 않는다. -
path A가 path B와
path-partmatch하지 않고, path B도 path A와path-partmatch하지 않는다.
-
-
"
Similar"를 반환한다.
A = 'nonce-ch4hvvbHDpv7xCSvXCs3BrNggHdTzxUA' B = 'nonce-ch4hvvbHDpv7xCSvXCs3BrNggHdTzxUA'
A와 B가 모두 nonce-source 문법과 일치하고 A가
B와
같으므로,
A는 B와 유사하다.
A = https://inner.example.com/foo/ B = http://*.example.com/foo/bar/
A가 wildcard host를 가지므로, 이 경우 "inner"인 모든 하위 도메인과 일치한다. 따라서 A는 B와 유사하다.
A = http://*.example.com B = https://inner.example.com:*
A와 B의 포트가 서로 다르더라도, "http"가 "http"와 더 안전한 변형인 "https" 모두와 일치하므로 A와 B는 유사하다.
A = http://example.com:80/page1/html B = https://example.com:443/
A와 B가 서로 다른 포트를 명시적으로 지정하므로, A는 B와 유사하지 않다.
A = 'sha256-abc123' B = 'sha512-cde456'
A와 B가 모두 hash-source 문법과 일치하더라도,
해시가 일치하지 않으므로 A는
B와 일치하지 않는다.
A = http://example.com:80 B = http://example.com:334
이 경우 A와 B의 포트가 일치하지 않으므로, 두 소스는 유사하지 않다.
A = http://example.com/page.html B = http://example.com/index.html
두 소스는 경로가 일치하지 않으므로 유사하지 않다.
3.2. 포섭
3.2.1. CSP 목록 포섭
Subsumes"를 반환하고, 그렇지 않으면
"Does Not Subsume"를 반환한다.
-
subsuming policy가
null이면, "Subsumes"를 반환한다. -
subsuming policy의 disposition이 "
report"이면, "Subsumes"를 반환한다. -
subsuming policy의 directive set이 비어 있으면, "
Subsumes"를 반환한다. -
policy list가 is empty이거나
null이면, "Does Not Subsume"를 반환한다. -
effective policy를 policy list와 origin이 주어졌을 때 § 3.1.1 CSP 목록 교집합을 실행한 결과로 둔다.
-
subsuming policy, subsuming origin, effective policy, 그리고 origin이 주어졌을 때 § 3.2.2 정책 포섭을 실행한 결과를 반환한다.
3.2.2. 정책 포섭
Subsumes"를 반환하고, 그렇지 않으면
"Does Not Subsume"를 반환한다.
-
A의 directive set이 비어 있으면, "
Subsumes"를 반환한다. -
A의 directive set에 있는 각 directive A에 대해:
-
directive name을 directive A의 name으로 둔다.
-
directive name이 "
default-src", "report-uri", "report-to"이면, 계속한다. -
effective directive A를 directive name과 A에 대한 유효 지시문 값으로 둔다.
-
effective directive B를 directive name과 B에 대한 유효 지시문 값으로 둔다.
-
effective directive A가
null이면, 계속한다. -
effective directive B가
null이면, "Does Not Subsume"를 반환한다. -
directive A의 name이 "
frame-ancestors"이면:-
effective directive B가 « "
'none'" »이면, 계속한다. -
effective directive A가 « "
'none'" »이면, "Does Not Subsume"를 반환한다. -
effective directive B의 각 expression B에 대해:
-
found match를
false로 둔다. -
effective directive A의 각 expression A에 대해:
-
expression A와 expression B가 주어졌을 때 § 3.2.4 소스 표현식 포섭이 "
Subsumes"를 반환하면, found match를true로 설정한다. 이 내부 루프에서 빠져나온다.
-
-
found match가
false이면, "Does Not Subsume"를 반환한다.
-
-
-
directive A의 name이 "
plugin-types"이면:-
effective directive B의 각 type B에 대해:
-
effective directive A가 type B를 포함하지 않으면, "
Does Not Subsume"를 반환한다.
-
-
-
directive A의 name이 "
sandbox"이면:-
flags A를 effective directive A가 주어졌을 때 sandboxing directive 파싱의 결과로 둔다.
-
flags B를 effective directive B가 주어졌을 때 sandboxing directive 파싱의 결과로 둔다.
-
flags A의 각 flag에 대해:
-
flags B가 flag를 포함하지 않으면, "
Does Not Subsume"를 반환한다.
-
참고: 정책 $A$는 $B$가 더 제한적인 경우 $B$를 포섭한다. sandbox 플래그의 경우, 이는 $A$가 허용하는 모든 권한이 $B$에서도 허용되어야 함을 의미한다. $B$가 $A$에 포함된 플래그를 생략하면, $B$는 해당 특정 권한에 대해 최소한 $A$만큼 제한적이지 않다.
-
-
그렇지 않으면:
-
effective directive A, origin A, directive name, effective directive B, origin B, 그리고 directive name이 주어졌을 때 § 3.2.3 소스 목록 포섭을 실행한 결과가 "
Does Not Subsume"이면, "Does Not Subsume"를 반환한다.
-
-
-
"
Subsumes"를 반환한다.
3.2.3. 소스 목록 포섭
Subsumes"를 반환하고, 그렇지 않으면
"Does Not Subsume"를 반환한다.
directive는 그 표현식이 자신의 value에 포함되어 있으면, 주어진 source expression을 포함한다.
-
directive A가 directive B와 ASCII 대소문자 구분 없음으로 일치하지 않으면, "
Does Not Subsume"를 반환한다. -
A가 비어 있거나 B가
none이면, "Subsumes"를 반환한다. -
B가 비어 있거나 A가
none이면, "Does Not Subsume"를 반환한다. -
directive B가 "
script-src"이고 B가keyword-source표현식 "strict-dynamic"을 포함하지만 A는 이를 포함하지 않으면, "Does Not Subsume"를 반환한다. -
directive B가 "
script-src" 또는 "style-src"이면:-
B가
keyword-source표현식 "unsafe-eval"을 포함하지만 A는 이를 포함하지 않으면, "Does Not Subsume"를 반환한다. -
B가
keyword-source표현식 "unsafe-hashed-attributes"를 포함하지만 A는 이를 포함하지 않으면, "Does Not Subsume"를 반환한다. -
type B를 directive B가 "
script-src"이면 "script", 그렇지 않으면 "style"로 둔다. 마찬가지로, type A를 directive A가 "script-src"이면 "script", 그렇지 않으면 "style"로 둔다. -
B와 type B가 주어졌을 때 Content Security Policy 3 § 6.7.3.2 Does a source list allow all inline behavior for type?가 "
Allows"를 반환하지만, A와 type A가 주어졌을 때 "Does Not Allow"를 반환하면, "Does Not Subsume"를 반환한다.
-
-
list A와 list B를 빈 목록으로 둔다.
-
A의 각 expression A에 대해:
-
expression A가 "
self"이면, origin A가 주어졌을 때 § 4.2.1 'self'를 origin에 대한 host-source 표현식으로 다시 쓰기.가 반환한host-source를 list A에 추가한다. -
expression A가 U+002A ASTERISK 문자(
*)와 일치하면, 다음scheme-source표현식들을 list A에 추가한다: "ftp:", "http:", "https:", "ws:", "wss:", 그리고 origin A의 scheme.-
directive A가 "
img-src" 또는 "media-src"이면,scheme-source표현식 "data:"를 list A에 추가한다. -
directive A가 "
media-src"이면,scheme-source표현식 "blob:"을 list A에 추가한다. -
다음 expression A로 계속한다.
-
-
expression A가
keyword-source문법과 일치하지 않으면, expression A를 list A에 추가한다.
-
-
B의 각 expression B에 대해:
-
expression B가 "
self"이면, origin B가 주어졌을 때 § 4.2.1 'self'를 origin에 대한 host-source 표현식으로 다시 쓰기.가 반환한host-source를 list B에 추가한다. -
expression B가 U+002A ASTERISK 문자(
*)와 일치하면, 다음scheme-source표현식들을 list B에 추가한다: "ftp:", "http:", "https:", "ws:", "wss:", 그리고 origin B의 scheme.-
directive B가 "
img-src" 또는 "media-src"이면,scheme-source표현식 "data:"를 list B에 추가한다. -
directive B가 "
media-src"이면,scheme-source표현식 "blob:"을 list B에 추가한다. -
다음 expression B로 계속한다.
-
-
expression B가
keyword-source문법과 일치하지 않으면, expression B를 list B에 추가한다.
-
-
list B가 비어 있으면, "
Subsumes"를 반환한다. -
list A가 비어 있으면, "
Does Not Subsume"를 반환한다. -
list B의 각 expression B에 대해:
-
expression B가
hash-source문법 또는nonce-source문법과 일치하면, directive A가 "script-src" 또는 "style-src"가 아닌 한 다음 expression으로 계속한다. -
found match를
false로 둔다. -
list A의 각 expression A에 대해:
-
expression A와 expression B가 주어졌을 때 § 3.2.4 소스 표현식 포섭이 "
Subsumes"를 반환하면, found match를true로 설정한다. 이 내부 루프에서 빠져나온다.
-
-
found match가
false이면, "Does Not Subsume"를 반환한다.
-
-
"
Subsumes"를 반환한다.
script-src"로 둔다. 다음
예제를 고려하라:
A = "http://example.com 'sha256-xzi4zkCjuC8'" B = "http://example.com"
B는 hash-source 표현식을 허용하지 않지만,
그 값이
A에서 발견되므로, A는 B를 포섭한다. 그러나 B가
A를
포섭한다는 것은 참이 아니다.
A = "https://example.com 'sha256-xzi4zkCjuC8'" B = "http://example.com"
이 경우 "https://example.com"은 "http://example.com"을 포섭하지 않으므로, A는 B를 포섭하지 않는다.
A = "http://example.com 'sha256-xzi4zkCjuC8'" B = "http://example.com 'unsafe-inline'"
B는 모든 인라인 동작을 허용하지만 A는 그렇지 않으므로, A는 B를 포섭하지 않는다.
A = "http://example.com 'sha256-xzi4zkCjuC8' 'strict-dynamic'" B = "http://example.com 'unsafe-inline' 'strict-dynamic'"
A와 B 모두 모든 인라인 동작을 허용하지 않는다. 이 경우 A는 B를 포섭한다.
3.2.4. 소스 표현식 포섭
Subsumes"를 반환하고, 그렇지
않으면
"Does Not Subsume"를 반환한다.
-
Assert: A와 B는 둘 다
keyword-source문법과 일치하지 않는다. -
A와 B가 모두
host-source또는scheme-source문법과 일치하면:-
A의
scheme-part(또는 A가scheme-part를 포함하지 않으면null)와 B의scheme-part(또는 B가scheme-part를 포함하지 않으면null)가 주어졌을 때 Content Security Policy 3 § 6.7.2.9 scheme-part matching이 "Does Not Match"를 반환하면, "Does Not Subsume"를 반환한다. -
A 또는 B가
scheme-source문법과 일치하면:-
A가
scheme-source문법과 일치하면, "Subsumes"를 반환한다. 그렇지 않으면, "Does Not Subsume"를 반환한다.
-
-
B가
wildcard host를 가지면:-
A가
wildcard host를 가지지 않으면, "Does not Subsume"를 반환한다. -
remaining host B를 B의
host-part에서 선행 ("*.") 을 제거한 결과로 둔다. -
A의
host-part와 remaining host B가 주어졌을 때 Content Security Policy 3 § 6.7.2.10 host-part matching이 "Does Not Match"를 반환하면, "Does Not Subsume"를 반환한다.
-
-
B가
wildcard host를 가지지 않고, A의host-part와 B의host-part가 주어졌을 때 Content Security Policy 3 § 6.7.2.10 host-part matching이 "Does Not Match"를 반환하면, "Does Not Subsume"를 반환한다. -
B가
wildcard port를 가지지만 A는wildcard port를 가지지 않으면, "Does Not Subsume"를 반환한다. -
B가
wildcard port를 가지지 않고, A의port-part(또는 A가port-part를 포함하지 않으면null)와 B의port-part(또는 B가port-part를 포함하지 않으면null)가 주어졌을 때 Content Security Policy 3 § 6.7.2.11 port-part matching이 "Does Not Match"를 반환하면, "Does Not Subsume"를 반환한다. -
A의
path-part(또는 A가path-part를 포함하지 않으면null)와 B의path-part(또는 B가path-part를 포함하지 않으면null)가 주어졌을 때 Content Security Policy 3 § 6.7.2.12 path-part matching이 "Does Not Match"를 반환하면, "Does Not Subsume"를 반환한다. -
"
Subsumes"를 반환한다.
-
-
A와 B가 모두
hash-source문법과 일치하면:-
A가 B와 같으면, "
Subsumes"를 반환한다. 그렇지 않으면 "Does Not Subsume"를 반환한다.
-
-
A와 B가 모두
nonce-source문법과 일치하면:-
"
Subsumes"를 반환한다.
참고: Nonce source 일치는 악의적인 임베더가 § 6.1 정책 누출에 설명된 공격으로 nonce 값을 무차별 대입하지 못하도록 값에 무관하다.
-
-
"
Does Not Subsume"를 반환한다.
nonce와 hash에 대한 포섭은 ('self' 또는 '*'와 'unsafe-inline'이 결합된 것처럼) 더 허용적인 소스가 논리적으로 이들을 포섭하는 경우를 고려하도록 갱신되어야 한다.
4. 알고리즘
4.1. request에 대한 response가 requiredCSP에 의해 차단되는가?
response (response), request
(request), 그리고 serialized CSP-또는-null
(requiredCSP)이 주어졌을 때, 이 알고리즘은 적절하게 "Allowed" 또는 "Blocked"를
반환한다:
-
requiredCSP가
null이면 "Allowed"를 반환한다. -
required policy를 requiredCSP를 "
enforce"로 파싱한 결과로 둔다. -
response와 request에 대해 실행했을 때 § 4.2 response는 request에서 온 정책의 포괄적 시행을 허용하는가? 알고리즘이 "
Allowed"를 반환하면, "Allowed"를 반환한다. -
required policy, response의 url의 origin, response의 Content Security Policies를 파싱한 결과, 그리고 response의 url의 origin에 대해 실행했을 때 § 3.2.1 CSP 목록 포섭 알고리즘이 "
Subsumes"를 반환하면, "Allowed"를 반환한다. -
"
Blocked"를 반환한다.
4.2. response는 request에서 온 정책의 포괄적 시행을 허용하는가?
response (response)와 request
(request)가 주어졌을 때, 이 알고리즘은 전자가 후자에게 임의의 정책을 시행하도록 허용하면
"Allowed"를 반환하고,
그렇지 않으면 "Not Allowed"를
반환한다:
-
response의 url의 scheme이 local scheme이면, "
Allowed"를 반환한다.참고: local scheme 응답은 이미 임베더에서 정책을 상속하므로, 이 임베딩 메커니즘을 통해 임베더가 해당 정책을 더 강화하도록 허용한다.
-
response의 header list에 `
Allow-CSP-From`라는 이름의 헤더(header)가 있으면: -
"
Not Allowed"를 반환한다.
4.2.1.
'self'를 origin에 대한 host-source 표현식으로 다시 쓴다.
origin (origin)이 주어졌을 때, 이 알고리즘은 해당 origin에 대해 'self'와 동일한 효과를
가지는 host-source 표현식을 반환한다:
-
origin이 opaque origin이면, 빈 문자열을 반환한다.
-
origin의 ASCII serialization을 반환한다.
5. 보안 고려사항
5.1. 위협 모델
이 제안은 문서가 자신이 임베드하는 자식 프레임에서 사용되는 콘텐츠를 제어할 수 있게 하는 것을 목표로 한다. 프레임은 일반적으로 그 자체로 보안 경계로 간주되며, cross-origin 접근을 의도적으로 제한하므로, 우리는 그 경계를 약화하지 않도록 해야 한다.
따라서 우리의 목표는 다음과 같다:
-
임베더가 자신이 임베드하는 임의의 문서에 콘텐츠 보안 정책 요구사항을 부과할 수 있게 한다.
-
주어진 콘텐츠 보안 정책 요구사항으로 로드된 문서가 (예를 들어 자신의 제어하에 있는 local scheme 문서를 통해) 이를 쉽게 벗어날 수 없도록 보장한다. 요구사항을 각 컨텍스트의 policy container에 넣으면 CSP 자체와 동일한 상속 구조에 의존할 수 있으며, 임베디 자신이 임베드하기로 선택할 수 있는 문서에 요구사항을 계속 부과할 수 있는 명확한 지점도 제공한다.
-
주어진 콘텐츠 보안 정책 요구사항으로 로드된 문서가 부과되는 요구사항을 확인할 수 있고, 명시적으로( `
Allow-CSP-From` 헤더를 통해) 또는 암시적으로( § 3 암시적 정책 수락에 설명된 메커니즘을 통해) 이에 옵트인하도록 보장한다. 이는 중요한 보안 인프라를 비활성화할 수 있는 악의적인 정책 요구사항으로부터 임베디를 보호한다. -
그리고 물론, 위의 작업을 새로운 취약점이나 위험을 도입하지 않고 수행한다.
이 제안은 CSP의
frame-ancestors나 X-Frame-Options 같은 기존 격리 메커니즘을 대체하려는 것이 아니며,
임베디에게
iframe
요소가 이미 나타내는 것 이상의 보호를 제공하지도 않는다.
5.2. 정책 시행
임베드된 문서는 제안된 콘텐츠 보안 정책을 신중하게 평가해야 하며, 임베더가 제안하는 정책을 단순히 반사해서는 안 된다. 그렇게 하면 영리한 공격자가 웹사이트 자체 보호에 필수적인 코드 일부를 선택적으로 비활성화할 수 있게 될 수 있다.
특히, 임베드될 것을 예상하지 않는 문서는 그러한 요청에 대해 계속해서 적절한
frame-ancestors
지시문을 포함하는 콘텐츠 보안 정책으로 응답해야 한다.
5.3. 헤더 반사
서버는
`Sec-Required-CSP`
헤더를
`Content-Security-Policy`
응답 헤더로 무조건 반사하는 것을 주의해야 한다. 부과된 정책은 결과 컨텍스트를 예상치 못한 방식으로
제한하거나, 서버가 달리 적용했을 정책보다 약할 수 있기 때문이다.
대신, 개발자는 신뢰할 수 있는 출처에 대해
`Allow-CSP-From`
헤더를 전달하여 수신 정책을 수락하기 전에 평가하는 것이 권장된다. 이렇게 하면 페이지가
적용하려는 정책은 적용되며, 그 위에 요구된 정책이 계층화된다. 여러 정책은 제한을 더 강화할 수밖에 없으므로,
이는 서버의 정책이 견고한 기준 보호로 유지되도록 보장한다.
5.4. 헤더 길이
이 기능은 임베더가 cross-origin 임베드 문서 요청에 대한
`Sec-Required-CSP`
HTTP 헤더의 값을 제어할 수 있게 한다. 서버가 HTTP 헤더 길이에 제한을 적용하는 경우,
이는 네트워크 오류를 일으킬 수 있다. 공격자는 이를 악용하여 캐시 무효화를 강제할 수 있다. 다음을 보라:
https://xsleaks.dev/docs/attacks/cache-probing/#cache-probing-with-error-events.
이 때문에 유효한 csp 속성의 최대 길이를 4KB로 제한한다.
6. 프라이버시 고려사항
6.1. 정책 누출
시행 메커니즘은 악의적인 임베더가 제약을 무차별 대입하여 페이지의 정책을 cross-origin으로 읽을 수 있게 한다. 정책에 비밀 토큰이나 사용자 이름이 포함되어 있다면, 이는 페이지나 페이지를 로드하는 사용자에 대한 흥미로운 데이터를 누출할 수 있다.
여기서도 최선의 방어는 적절한 frame-ancestors 지시문을 통해
주어진 리소스를 임베드할 수 있는 컨텍스트를 제어하는 것이다.
6.2. 데이터 유출
이 기능은 임베더가
`Sec-Required-CSP`
HTTP 헤더를 통해 제3자 엔드포인트로 정보를 보낼 수 있게 한다. 이는 HTTP 요청 자체(GET 매개변수 등)를 통해
터널링할 수 없는 정보를 노출하는 것으로 보이지 않으며, 임베더는 적절한 child-src 지시문이 있는
콘텐츠 보안 정책을 시행함으로써 그러한 요청이 이루어질 수 있는 엔드포인트를 계속 제어한다.
7. 작성 고려사항
7.1.
'self' 요구하기
required CSP를 처리할 때, 키워드 'self'는
정책을 요구한 문서의 origin이 아니라,
child navigable에 로드되는 URL의
origin을 가리킨다.
https://example.com/page.html의 페이지에서 'self'를 포함하는 정책을 요구한다:
<iframe src="https://advertisements-r-us.example.com/ad1.cfm"
csp="script-src 'self'">
</iframe>
반환된 CSP가 다음과 같다면:
Content-Security-Policy: script-src 'self'
그러면 이
iframe
요소는 로드된다.
그러나 반환된 CSP가 다음과 같다면:
Content-Security-Policy: script-src "https://example.com/"
그러면 이
iframe
요소는 로드되지 않는다.
8. IANA 고려사항
영구 메시지 헤더 필드 레지스트리는
`Sec-Required-CSP`
헤더에 대한 다음 등록으로 갱신되어야 한다:
[RFC3864]
- 헤더 필드 이름
-
Sec-Required-CSP
- 적용 가능한 프로토콜
-
http
- 상태
-
standard
- 작성자/변경 관리자
-
W3C
- 명세 문서
-
이 명세 (§ 2.2 Sec-Required-CSP HTTP 요청 헤더 참조)
마찬가지로, 레지스트리는
`Allow-CSP-From`
헤더에 대한 다음 등록으로 갱신되어야 한다:
[RFC3864]
- 헤더 필드 이름
-
Allow-CSP-From
- 적용 가능한 프로토콜
-
http
- 상태
-
standard
- 작성자/변경 관리자
-
W3C
- 명세 문서
-
이 명세 (§ 2.3 Allow-CSP-From HTTP 응답 헤더 참조)