1. 소개
웹의 사이트와 애플리케이션은 단일 출처의 리소스만으로 구성되는 경우가 거의 없습니다. 예를 들어, 작성자는 다양한 서비스와 콘텐츠 전송 네트워크(CDN)에서 스크립트와 스타일을 가져오며, 실제로 전달된 표현이 자신이 기대했던 것과 동일하다는 것을 신뢰해야 합니다. 만약 공격자가 DNS [RFC1035] 오염 또는 기타 방법을 통해 사용자가 악의적인 서버로부터 콘텐츠를 다운로드하도록 속인다면, 작성자는 대응할 방법이 없습니다. 마찬가지로, 공격자가 CDN 서버의 파일을 교체할 수 있다면 임의의 콘텐츠를 주입할 수 있습니다.
보안 채널을 통해 리소스를 전달하면 이러한 위험이 어느 정도 완화됩니다. TLS [TLS], HSTS [RFC6797], 그리고 공개키 고정 [RFC7469]을 통해 사용자 에이전트는 자신이 실제로 의도한 서버와 통신하고 있음을 상당히 확신할 수 있습니다. 하지만 이러한 메커니즘은 서버만 인증할 뿐, 콘텐츠 자체는 인증하지 않습니다. 서버에 접근할 수 있는 공격자(혹은 관리자)는 콘텐츠를 자유롭게 조작할 수 있습니다. 이상적으로는 작성자가 서버의 키뿐만 아니라 콘텐츠도 고정(pin)하여, 특정 리소스의 정확한 표현만이 로드 및 실행되도록 보장할 수 있어야 합니다.
이 문서에서는 이런 검증 방식을 명세하며, 두 HTML 요소에 integrity
속성을 확장하여 작성자가 로드하려는 리소스 표현의 암호학적 해시를 포함할 수 있도록 합니다.
예를 들어, 작성자가 프레임워크를 자신의 출처가 아닌 공유 서버에서 로드하고자 할 때, https://example.com/example-framework.js
의
예상되는 SHA-384 해시가 Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7
임을
명시하면, 사용자 에이전트는 해당 URL에서 로드한 데이터가 기대하는 해시와 일치하는지 확인한 뒤 JavaScript를 실행합니다. 이 무결성 검증은 공격자가 악의적인 콘텐츠로 대체할 위험을
크게 줄여줍니다.
이 예시는 script
요소에 해시를 추가하여 사용자 에이전트에 전달할 수 있습니다:
< script src = "https://example.com/example-framework.js" integrity = "sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7" crossorigin = "anonymous" ></ script >
무결성 검증의 혜택을 받을 수 있는 응답 유형은 스크립트만이 아닙니다. 여기서 명세된 방식은 link
에도 적용되며, 향후 명세서 버전에서 적용 범위가 더욱 확대될 수
있습니다.
1.1. 목표
-
서드파티 서비스가 침해되더라도 해당 서비스를 포함한 모든 사이트가 자동으로 침해되는 것은 아니어야 합니다. 콘텐츠 작성자는 로드하는 콘텐츠에 대한 기대를 명확히 지정할 수 있는 메커니즘을 갖게 되므로, 예를 들어 특정 스크립트만 로드하고, 단순히 해당 URL을 가진 아무 스크립트가 로드되는 일이 없도록 할 수 있습니다.
-
검증 메커니즘은 잘못된 응답이 수신된 경우 작성자에게 알릴 수 있는 오류 보고 기능을 제공해야 합니다.
1.2. 사용 사례/예시
1.2.1. 리소스 무결성
-
작성자는 전 세계적으로 분산된 사용자에게 성능을 개선하기 위해 콘텐츠 전송 네트워크(CDN)를 사용하고자 합니다. 하지만 CDN의 서버가 작성자가 기대하는 코드만을 제공하도록 보장하는 것이 중요합니다. CDN이 침해되거나 예상치 못한 악의적 동작이 발생해 사이트가 변조되는 위험을 완화하기 위해, 다음과 같이 페이지에 포함된
link
요소에 무결성 메타데이터를 추가합니다: -
작성자는 서드파티 분석 서비스에서 제공하는 JavaScript를 포함하고자 합니다. 신중히 검토된 코드만 실행되도록 하기 위해 작성자는 해당 스크립트에 대한 무결성 메타데이터를 생성하여
script
요소에 추가합니다: -
사용자 에이전트는 고권한 HTML 컨텍스트(예: 브라우저의 새 탭 페이지)에서 실행되는 JavaScript 코드가 표시 전 변조되지 않도록 보장하고자 합니다. 무결성 메타데이터는 변경된 JavaScript가 이러한 고권한 페이지에서 실행될 위험을 완화합니다.
2. 핵심 개념 및 용어
이 섹션에서는 문서 전체에서 사용되는 여러 용어를 정의합니다.
digest라는 용어는 임의의 데이터 블록에 대해 암호화 해시 함수를 실행한 결과를 base64로 인코딩한 값을 의미합니다.
origin과 same origin이라는 용어는 HTML에서 정의됩니다. [HTML]
base64 인코딩은 RFC 4648 4절에서 정의됩니다. [RFC4648]
SHA-256, SHA-384, SHA-512는 NIST에서 정의한 SHA-2 암호화 해시 함수 집합의 일부입니다. [SHA2]
유효한 SRI 해시
알고리즘 토큰 집합은 순서가 지정된 집합 « "sha256
", "sha384
",
"sha512
" »입니다(각각 SHA-256, SHA-384, SHA-512에 해당). 이 집합의 순서는 의미가 있으며, 더 강력한 알고리즘이 뒤에 위치합니다. 자세한 내용은 § 3.2.2 우선순위와 § 3.3.3 집합에서 가장 강력한 메타데이터
얻기를 참고하세요.
문자열이 유효한 SRI 해시 알고리즘 토큰이려면, 해당 문자열의 ASCII 소문자가 포함되어야 하며, 유효한 SRI 해시 알고리즘 토큰 집합에 속해야 합니다.
2.1. 문법적 개념
이 문서에서 사용된 확장된 바커스-나우어 형식(ABNF) 표기는 RFC5234에서 명시되어 있습니다. [ABNF]
RFC5234 부록 B.1에서는 VCHAR(출력 문자)와 WSP(공백) 규칙을 정의합니다.
Content Security Policy에서는 base64-value
와 hash-algorithm
규칙을 정의합니다. [CSP]
3. 프레임워크
여기서 명세된 무결성 검증 메커니즘은 리소스에 대해 충분히 강력한 암호화 digest를 생성하고, 해당 digest를 사용자 에이전트로 전달하여 응답을 검증하는 과정으로 요약됩니다.
3.1. 무결성 메타데이터
응답의 무결성을 검증하려면, 사용자 에이전트는 무결성 메타데이터를 요청의 일부로 필요로 합니다. 이 메타데이터는 다음 정보를 포함합니다:
-
암호화 해시 함수("alg")
-
digest("val")
-
옵션("opt")
응답의 무결성을 검증하려면 해시 함수와 digest가 반드시 제공되어야 합니다.
참고: 현재는 옵션이 정의되어 있지 않습니다. 하지만 향후 명세에서는 MIME 타입[MIME-TYPES] 등과 같은 옵션이 정의될 수 있습니다.
이 메타데이터는 hash-source
(단일 인용부호 제외)와 동일한 형식으로 인코딩되어야 하며, 자세한 내용은 Content Security Policy Level 2 명세 4.2절을
참고하세요.
예를 들어, alert('Hello, world.');
라는 문자열만 포함된 스크립트 리소스에 대해 작성자가 SHA-384 해시 함수를 선택했다면,
H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO
가 생성된 base64 인코딩된 digest가 됩니다. 다음과 같이 인코딩할 수 있습니다:
echo -n"alert('Hello, world.');" | openssl dgst -sha384 -binary| openssl base64 -A
3.2. 암호화 해시 함수
적합한 사용자 에이전트는 SHA-256, SHA-384, SHA-512 암호화 해시 함수를 무결성 메타데이터의 일부로 지원해야 하며, 향후 명세에서 정의되는 추가 해시 함수도 지원할 수 있습니다.
참고: 현재 이 문서에서 지원하는 알고리즘은 두 번째 원상 이미지 공격(second-preimage attack)과 충돌 공격에 대해 안전한 것으로 여겨집니다. 향후 지원 알고리즘 추가/삭제 시에도 유사한 기준을 적용하는 것이 바람직합니다. 자세한 내용은 § 5.2 해시 충돌 공격을 참고하세요.
3.2.1. 유연성
향후 암호학적 변화에 대응할 수 있도록 하나의 리소스에 여러 집합의 무결성 메타데이터를 연결할 수 있습니다. 예를 들어, 앞에서 설명한 리소스는 다음 해시 표현식들로 설명될 수 있습니다:
sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw==
작성자는 예를 들어 다음과 같이 둘 다 명시할 수 있습니다:
< script src = "hello_world.js" integrity = "sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw==" crossorigin = "anonymous" ></ script >
이 경우, 사용자 에이전트는 목록에서 가장 강력한 해시 함수를 선택하여 해당 메타데이터로 응답을 검증합니다(아래 § 3.3.2 메타데이터 파싱 및 § 3.3.3 집합에서 가장 강력한 메타데이터 얻기 알고리즘 참조).
해시 함수가 안전하지 않은 것으로 판명되면, 사용자 에이전트는 해당 해시 함수로 무결성 검증을 지원하지 않도록 점진적으로 사용 중단(deprecate)하고, 결국 지원을 제거해야 합니다. 사용자 에이전트는 사용 중단된 함수 기반 digest로 응답의 유효성을 확인할 수도 있습니다.
작성자가 더 강력한 해시 함수로 전환할 수 있도록, 지원되지 않는 해시 함수로 검증하면 무결성 값이 제공되지 않은 것과 동일하게 동작합니다(아래 § 3.3.4 bytes가 metadataList와 일치하는지 확인 알고리즘 참조). 작성자에게는 강력한 해시 함수를 사용할 것을 권장하며, 새로 이용 가능한 함수로 미리 마이그레이션할 것을 추천합니다.
3.2.2. 우선순위
해시 알고리즘의 우선순위는 유효한 SRI 해시 알고리즘 토큰 집합에서 각 토큰의 순서로 지정됩니다. 집합에서 앞에 위치한 알고리즘이 뒤에 있는 알고리즘보다 약합니다.
현재 명세에 따르면, SHA-256은 SHA-384보다 약하며, SHA-512가 가장 강력합니다. 현재 명세에서는 다른 해시 알고리즘은 지원하지 않습니다.
3.3. 응답 검증 알고리즘
3.3.1. algorithm을 bytes에 적용
-
algorithm을 bytes에 적용한 결과를 result로 한다.
-
result를 base64 인코딩한 결과를 반환한다.
3.3.2. 메타데이터 파싱
문자열 metadata가 주어질 때 메타데이터 파싱을 요청받으면, 다음 단계에 따라 동작합니다:
참고: 이 알고리즘은 사용자 에이전트가 이해할 수 있는 해시 표현식 집합을 반환합니다.
-
result를 빈 집합으로 한다.
-
metadata를 공백 기준으로 분할한 결과 각각 item에 대해:
-
expression-and-options를 ?(U+003F) 기준으로 item을 분할한 결과로 한다.
-
algorithm-expression을 expression-and-options[0]으로 한다.
-
base64-value를 빈 문자열로 한다.
-
algorithm-and-value를 -(U+002D) 기준으로 algorithm-expression을 분할한 결과로 한다.
-
algorithm을 algorithm-and-value[0]으로 한다.
-
algorithm이 유효한 SRI 해시 알고리즘 토큰이 아니면 다음 반복으로 이동한다.
-
algorithm-and-value[1]이 존재하면, base64-value를 algorithm-and-value[1]로 설정한다.
-
metadata를 «["alg" → algorithm, "val" → base64-value]» 형태의 순서가 지정된 맵으로 한다.
참고:
options
가 정의되어 있지 않으므로(§ 3.1 무결성 메타데이터 참고), metadata에 해당 항목을 설정하지 않습니다. 향후 명세에서 옵션이 정의되면 expression-and-options[1]을options
로 사용할 수 있습니다. -
추가 metadata를 result에 한다.
-
-
result를 반환한다.
3.3.3. set에서 가장 강력한 메타데이터 얻기
-
result를 빈 집합으로, strongest를 null로 한다.
-
set의 각 item에 대해:
-
단언: item["
alg
"]는 유효한 SRI 해시 알고리즘 토큰이다. -
result가 빈 집합이면, 다음을 수행한다:
-
currentAlgorithm을 strongest["
alg
"], currentAlgorithmIndex를 currentAlgorithm이 유효한 SRI 해시 알고리즘 토큰 집합에서의 인덱스로 한다. -
newAlgorithm을 item["
alg
"], newAlgorithmIndex를 newAlgorithm이 유효한 SRI 해시 알고리즘 토큰 집합에서의 인덱스로 한다. -
newAlgorithmIndex가 currentAlgorithmIndex보다 작으면, 다음 반복으로 이동한다.
-
그렇지 않고 newAlgorithmIndex가 currentAlgorithmIndex보다 크면:
-
strongest를 item으로 한다.
-
result를 « item »로 한다.
-
-
그 밖의 경우, newAlgorithmIndex와 currentAlgorithmIndex가 동일한 값이라면, 추가 item을 result에 한다.
-
-
result를 반환한다.
3.3.4. bytes가 metadataList와 일치하는지 확인
-
parsedMetadata를 metadataList 파싱 결과로 한다.
-
parsedMetadata가 빈 집합이면,
true
를 반환한다. -
metadata를 parsedMetadata에서 가장 강력한 메타데이터 얻기 결과로 한다.
-
metadata의 각 item에 대해:
-
algorithm을 item["alg"]로 한다.
-
expectedValue를 item["val"]로 한다.
-
actualValue를 algorithm을 bytes에 적용한 결과로 한다.
-
actualValue가 expectedValue와 대소문자 구분 일치하면,
true
를 반환한다.
-
-
false
를 반환한다.
이 알고리즘은 사용자 에이전트가 여러 개의 유효한 강력한 해시 함수를 허용할 수 있게 합니다. 예를 들어, 개발자가 다음과 같은 script
요소를 작성할 수 있습니다:
< script src = "https://example.com/example-framework.js" integrity = "sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7 sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB" crossorigin = "anonymous" ></ script >
이 경우 사용자 에이전트는 첫 번째 SHA-384 해시 값과 두 번째 SHA-384 해시 값 중 하나에 일치하는 두 가지 서로 다른 콘텐츠 페이로드를 허용할 수 있습니다.
참고: 사용자 에이전트는 사용자 환경설정, 북마클릿, 서드파티 추가 기능 등 다양한 방식으로 이 알고리즘의 결과를 수정할 수 있습니다. 예를 들어, HTTPS Everywhere와 같은 확장 프로그램에서 생성된 리디렉션은 HTTP와 HTTPS 리소스가 다르더라도 정상적으로 로드 및 실행될 수 있습니다.
참고: 서브리소스 무결성은 CORS가 필수이며, CORS 없이 사용하려 하면 논리적 오류가 발생합니다. 사용자 에이전트는 개발자 콘솔에 경고 메시지를 출력하여 실패 원인을 안내하는 것이 권장됩니다. [Fetch]
3.4. HTML 문서 서브리소스 검증
다양한 HTML 요소는 문서에 삽입되거나 문맥에서 실행되어야 하는 리소스를 요청합니다. 이러한 요소 중 일부에 대해 무결성 메타데이터를 지원하기 위해 link
와
script
요소의 콘텐츠 속성 목록에 새로운 integrity
속성이 추가되었습니다. [HTML]
참고: 향후 명세 개정판에서는 모든 가능한 서브리소스(a
,
audio
, embed
, iframe
, img
, link
,
object
, script
, source
, track
, video
요소)까지
무결성 지원을 포함할 가능성이 높습니다.
3.5. integrity
속성
integrity
속성은 해당 요소의 무결성 메타데이터를 나타냅니다.
속성 값은 빈 문자열이거나 아래 ABNF 문법에 따라 적어도 하나의 유효한 메타데이터여야 합니다:
integrity-metadata = *WSP hash-with-options *(1*WSP hash-with-options ) *WSP / *WSP hash-with-options = hash-expression *("?" option-expression) option-expression = *VCHAR hash-expression = hash-algorithm "-" base64-value
option-expression
은 각 hash-expression
단위로 연결되며, 바로 앞의 hash-expression
에만
적용됩니다.
사용자 에이전트가 향후 옵션에 완전히 호환되도록 하려면, 인식하지 못한 option-expression
은 반드시 무시해야 합니다.
참고: option-expression
이 문법에 예약되어 있지만 현재는 옵션이
정의되지 않았습니다. 향후 명세 개정에서 보다 구체적인 옵션 문법이 정의될 가능성이 높으므로 여기서는 최대한 넓게 정의되어 있습니다.
3.6.
integrity
링크 처리 옵션
무결성 메타데이터는
`link
`
HTTP 응답 헤더에서도 integrity
링크 파라미터로 지정할 수 있으며, 반드시 요소의 integrity
속성과 동일한 integrity-metadata
문법을 사용해야 합니다. 예시:
Link: </style.css>; rel=preload; as=style; crossorigin="anonymous"; integrity="sha256-[digest goes here]"
3.7. 무결성 위반 처리
사용자 에이전트는 무결성 검증에 실패한 응답은 렌더링하거나 실행하지 않고, 대신 Fetch에서 정의된 네트워크 오류를 반환합니다. [Fetch]
참고: 무결성 검증 실패 시 error
이벤트가 발생합니다. 개발자가 표준
대체 리소스(예: CDN이 아닌 신뢰할 수 있지만 느린 출처에서 제공되는 리소스)를 제공하고 싶다면 error
이벤트를 캐치하여 실패한 리소스를 다른 리소스로 대체하는
핸들러를 구현할 수 있습니다.
3.8. Integrity-Policy
Integrity-Policy
와 Integrity-Policy-Report-Only
HTTP 헤더는 문서가 특정 destination에 대해 로드하는 모든 서브리소스에 대해 무결성 메타데이터 요구 정책을 적용할 수 있도록
합니다.
헤더 값은 Dictionary [RFC9651]이며, 각 멤버 값은 inner list 타입 token들의 리스트입니다.
source는 문자열이며, 가능한 값은
"inline
"뿐입니다.
destination은 destination type이며, 값은 "script
"와 "style
"입니다.
무결성 정책은 다음을 포함하는 struct입니다:
-
sources는 source들의 리스트이며, 처음에는 비어 있습니다.
-
blocked destinations는 destination들의 리스트이며, 처음에는 비어 있습니다.
-
endpoints는 문자열 리스트이며, 처음에는 비어 있습니다.
무결성 정책 처리 시, header list headers와 header name headerName이 주어지면 다음을 수행합니다:
-
integrityPolicy를 새로운 무결성 정책으로 한다.
-
dictionary를 structured field value 얻기로 headers, headerName, "
dictionary
"를 전달하여 얻는다. -
dictionary["
sources
"]가 존재하지 않거나 값에 "inline"이 포함되어 있으면, 추가 "inline
"을 integrityPolicy의 sources에 한다. -
dictionary["
blocked-destinations
"]가 존재하면:-
값에 "script"가 포함되어 있으면, 추가 "
script
"를 integrityPolicy의 blocked destinations에 한다. -
값에 "style"이 포함되어 있으면, 추가 "
style
"를 integrityPolicy의 blocked destinations에 한다.
-
-
dictionary["
endpoints
"]가 존재하면:-
integrityPolicy의 endpoints를 dictionary['endpoints']로 설정한다.
-
-
integrityPolicy를 반환한다.
Integrity-Policy: blocked-destinations=(script), endpoints=(integrity-endpoint)
이 차단은 "integrity-endpoint
" 보고 엔드포인트(관련 Reporting-Endpoints
헤더로 정의됨)에도 보고를
트리거합니다.
개발자는 "integrity-violation
"에 대해 JavaScript 기반 보고를 위해 ReportingObserver를 등록할 수도 있습니다.
3.8.1. Integrity-Policy 헤더 파싱
Integrity-Policy 헤더 파싱을 하려면, Response response와 policy container container가 주어졌을 때 다음을 수행한다:-
headers를 response의 header list로 한다.
-
headers가 integrity-policy를 포함하면, container의 integrity policy를 해당 무결성 정책 처리 결과로 설정한다. 값은 해당 헤더 값을 사용한다.
-
headers가 integrity-policy-report-only를 포함하면, container의 보고 전용 무결성 정책을 해당 무결성 정책 처리 결과로 설정한다. 값은 해당 헤더 값을 사용한다.
3.8.2. Integrity Policy에 의해 요청 차단 여부
Integrity Policy에 의해 요청이 차단되어야 하는지 판단을 하려면, request request가 주어졌을 때 다음을 수행한다:-
policyContainer를 request의 policy container로 한다.
-
parsedMetadata를 parse metadata를 request의 integrity metadata로 호출한 결과로 한다.
-
parsedMetadata가 빈 집합이 아니고 request의 mode가 "
cors
" 또는 "same-origin
"이면, "Allowed"를 반환한다. -
policy를 policyContainer의 integrity policy로 한다.
-
reportPolicy를 policyContainer의 보고 전용 무결성 정책으로 한다.
-
policy와 reportPolicy가 모두 빈 무결성 정책이면, "Allowed"를 반환한다.
-
global을 request의 client의 global object로 한다.
-
global이
Window
또는WorkerGlobalScope
가 아니면, "Allowed"를 반환한다. -
block을 boolean false로 초기화한다.
-
reportBlock을 boolean false로 초기화한다.
-
policy의 sources가 "
inline
"을 포함하고, policy의 blocked destinations가 request의 destination을 포함하면, block을 true로 한다. -
reportPolicy의 sources가 "
inline
"을 포함하고, reportPolicy의 blocked destinations가 request의 destination을 포함하면, reportBlock을 true로 한다. -
block이 true이거나 reportBlock이 true이면, report violation을 request, block, reportBlock, policy, reportPolicy로 실행한다.
-
block이 true이면 "
Blocked
"를 반환하고, 그렇지 않으면 "Allowed
"를 반환한다.
3.8.3. 위반 보고
dictionary :
IntegrityViolationReportBody ReportBody {USVString ;
documentURL USVString ;
blockedURL USVString ;
destination boolean ; };
reportOnly
위반 보고를 하려면, Request request, boolean block, boolean reportBlock, 무결성 정책 policy, 무결성 정책 reportPolicy가 주어졌을 때 다음을 실행한다:
-
settingsObject를 request의 client로 한다.
-
global을 settingsObject의 global object로 한다.
-
단언: global은
Window
또는WorkerGlobalScope
이다. -
url을 null로 한다.
-
global이
Window
이면, url을 global의 연결된 Document의URL
로 한다. -
global이
WorkerGlobalScope
이면, url을 global의 URL로 한다. -
documentURL를 url에 대해 report용 URL 변환 결과로 한다.
-
blockedURL를 request의 URL에 보고용 URL 변환(strip URL for use in reports)을 적용한 결과로 한다.
-
block이 true이면, policy의 endpoints 각각 endpoint에 대해:
-
body를 다음과 같이 초기화된 새로운
IntegrityViolationReportBody
로 한다:documentURL
-
documentURL
blockedURL
-
blockedURL
destination
-
request의 destination
reportOnly
-
false
-
Generate and queue a report를 다음 인자로 실행한다:
- context
-
settingsObject
- type
-
"
integrity-violation
" - destination
-
endpoint
- data
-
body
-
-
-
reportBody를 다음과 같이 초기화된 새로운
IntegrityViolationReportBody
로 한다:documentURL
-
documentURL
blockedURL
-
blockedURL
destination
-
request의 destination
reportOnly
-
true
-
Generate and queue a report를 다음 인자로 실행한다:
- context
-
settingsObject
- type
-
"
integrity-violation
" - destination
-
endpoint
- data
-
reportBody
-
4. 프록시
응답을 수정하는 최적화 프록시 및 기타 중간 서버는 해당 응답과 연결된 digest가 새 콘텐츠와 동기화되어 있는지 반드시 보장해야 합니다. 한 가지 방법은 리소스와 연결된 무결성 메타데이터를 업데이트하는 것이고, 또 다른 방법은 페이지 작성자가 무결성 검증을 요청한 리소스의 정본(canonical) 버전만 전달하는 것입니다.
중간 서버에게 정보를 제공하기 위해, 리소스를 제공하는 서버는 리소스와 함께 Cache-Control
헤더를 no-transform
값과 함께 전송해야 합니다.
5. 보안 및 개인정보 고려사항
이 섹션은 규범적이지 않습니다.
5.1. 비보안 컨텍스트는 여전히 비보안
무결성 메타데이터가 HTTP 페이지 등 보안 컨텍스트가 아닌 곳에서 전달된다면, 외부 리소스가 호스팅된 서버가 침해된 경우에만 원본 보호가 이루어집니다. 네트워크 공격자는 digest를 전송 중에 변경(혹은 완전히 제거 또는 문서에 대해 어떤 조작도)할 수 있으므로, 해시가 검증하는 응답과 마찬가지로 문서를 변조할 수 있습니다. 따라서 작성자는 보안 컨텍스트에서만 무결성 메타데이터를 제공할 것을 권장합니다. 웹 보안화 지침도 참고하세요.
5.2. 해시 충돌 공격
Digest의 강도는 사용된 해시 함수의 강도에 따라 달라집니다. 사용자 에이전트는 알려진 약한 해시 함수를 지원하지 않도록 해야 하며, 충돌 저항성이 입증된 알고리즘만 지원하도록 제한하는 것이 좋습니다. 권장되지 않는 해시 함수의 예로는 MD5와 SHA-1이 있습니다. 작성 시점 기준으로 SHA-384는 좋은 기준선입니다.
또한, 사용자 에이전트는 지원하는 해시 함수를 정기적으로 재평가하고, 안전하지 않은 것으로 판명된 함수는 사용 중단해야 합니다. 시간이 지나면서 해시 함수가 예상보다 훨씬 약하거나, 완전히 깨지는 경우가 있으므로, 사용자 에이전트가 이러한 발전 상황을 인지하는 것이 중요합니다.
5.3. 교차 출처 데이터 유출
이 명세서는 무결성 보호된 교차 출처 요청에 대해 리소스의 콘텐츠가 명시적으로 요청자에게 공유되도록 CORS 프로토콜 사용을 요구합니다. 이 요구가 없으면 공격자는 동일 출처 정책을 위반하고 교차 출처 리소스의 특정 콘텐츠 여부를 알아낼 수 있습니다.
공격자는 알려진 digest로 리소스를 로드하려 시도하고, 로드 실패를 관찰합니다. 로드가 실패하면 응답이 해시와 일치하지 않는다는 것을 추론하여 일부 내용을 파악할 수 있습니다. 예를 들어 특정 서비스에 사용자가 로그인했는지 여부를 알 수 있습니다.
또한 공격자는 거의 고정된 리소스에서 특정 값을 무차별 대입(brute-force)할 수 있습니다. 다음과 같은 JSON 응답을 예로 들어보세요:
공격자는 여러 일반적인 사용자 이름에 대해 응답의 해시를 미리 계산해두고, 해당 해시들을 지정하며 문서를 반복적으로 로드하려 시도할 수 있습니다. 성공적으로 로드되면 공격자가 사용자 이름을 맞췄음을 확인할 수 있습니다.
6. 감사의 말씀
여기 내용의 많은 부분은 Gervase Markham의 링크 지문(Link Fingerprints) 개념과 WHATWG의 링크 해시(Link Hashes)에서 많은 영감을 받았습니다.
이 명세 초기 버전에 큰 기여를 해준 Mike West에게 특별히 감사드립니다. Brad Hill, Anne van Kesteren, Jonathan Kingston, Fatih Kilic, Mark Nottingham, Sergey Shekyan, Dan Veditz, Eduardo Vela, Tanvi Vyas, Yoav Weiss, Michal Zalewski에게도 귀중한 피드백을 제공해주셔서 감사합니다.