Posts Content-Security-Policy(CSP) 살펴보기
Post
Cancel

Content-Security-Policy(CSP) 살펴보기

Content-Security-Policy ?

콘텐츠 보안 정책(CSP)은 특정 유형의 보안 위협의 위험을 방지하거나 최소화하는 데 도움이 되는 기능으로
웹사이트에서 브라우저로 보내는 일련의 지침으로 구성되어 있으며, 브라우저에서 코드가 수행할 수 있는 작업에 제한을 두도록 지시

CSP 전달 방식

  • HTTP 응답 헤더
    • 메인 문서뿐만 아니라 모든 요청에 대한 응답에 적용되어야 한다.
  • <meta> 태그의 http-equiv 속성으로 정의

정책

  • 정책은 세미콜론으로 구분된 일련의 지시문(Fetch directives)으로 구성
  • 각 지시문은 보안 정책의 다른 측면을 제어

예시

Content-Security-Policy: default-src 'self'; img-src 'self' example.com

  • 지시문1 : default-src 'self'
    • 다른 리소스 유형에 대해 다른 정책을 설정하는 구체적인 지시어가 없는 한, 문서와 동일한 출처의 리소스만 로드하라고 브라우저에 지시
  • 지시문2 : img-src 'self' example.com
    • 브라우저에 동일한 출처의 이미지나 example.com에서 제공된 이미지를 로드하라고 지시

Fetch directives

리소스(JavaScript, CSS, 이미지 등)에 대한 허용된 범주(도메인, URL, 프로토콜, 또는 패턴 등)를 지정
예를 들어, script-src는 JavaScript 로드를 허용하는 범주를 설정
전체 지시어 목록은 여기에서 확인할 수 있다.

  • default-src : 지시문이 명시적으로 나열되지 않은 모든 리소스에 대한 대체 정책을 설정

  • 각 Fetch directives는 단일 키워드 'none' 또는 공백으로 구분된 하나 이상의 출처 표현식(source expressions)으로 지정

    • none : 해당 리소스 로드 자체를 차단
    • self : 문서 자체와 동일한 출처(origin)의 리소스만 허용
    • 두 개 이상의 출처 표현식이 나열된 경우 하나라도 리소스를 허용하면 리소스가 허용됨
      • 하지만, 예외적으로 none이 같이 있으면 다른 출처 표현식들은 무시됨

예시

Content-Security-Policy: default-src 'self'; img-src 'self' example.com

  • default-src는 단일 출처 표현식 self로 구성.
  • img-src는 두 개의 출처 표현식 self와 example.com으로 구성

※ Fetch ?

  • fetch는 일반적으로 영어에서 “가져오다” 또는 “불러오다”라는 의미
  • fetch는 브라우저가 외부 리소스를 요청하거나 가져오는 행위
  • 즉, Fetch directives란 웹 문서가 불러올 수 있는 리소스의 종류나 출처를 제한하는 지시어

출처 표현식 형식 살펴보기

<host-source><scheme-source> 형식은 따옴표로 묶어서는 안되며, 다른 모든 형식은 작은 따옴표로 묶어야 한다.

<host-source>

해당 리소스를 허용할 출처의 URL 또는 호스트 IP 주소

  • 스키마(예: http, https), 포트 번호, 경로(path)는 생략할 수 있다.
    • origin = <scheme> "://" <host> [ ":" <port> ]
  • 스키마를 생략하면, 문서의 출처(origin)에서 사용된 스키마가 자동으로 적용된다.
    • 예를 들어, iframe에서 Content-Security-Policy: frame-ancestors *.example.com으로 설정했고 iframe의 url 스키마가 https라면 부모창도 반드시 https 여야한다.
  • CSP(Content-Security-Policy)에서 스키마를 지정하면 원칙적으로는 정확한 일치가 요구되지만, 보안 단계가 더 높은 스키마로 업그레이드된 요청은 자동으로 허용된다.
    • http://example.comhttps://example.com의 리소스도 허용
    • ws://example.comwss://example.org의 리소스도 허용
  • 와일드카드(*)는 서브도메인, 호스트 주소 및 포트 번호에서 사용할 수 있으며, 각 항목에서 가능한 모든 유효한 값이 허용됨을 의미한다.
    • http://*.example.comexample.com의 모든 서브도메인으로부터 오는 리소스를 HTTP 또는 HTTPS로 허용
  • 경로가 /로 끝나는 경우, 그 경로로 시작하는 모든 하위 경로를 매칭한다.
    • example.com/api/는 다음과 같은 경로 모두 허용:
      • example.com/api/users
      • example.com/api/users/list
      • example.com/api/orders/123
  • 만약 경로가 /로 끝나지 않는다면, 정확히 그 경로 하나만 매칭한다.
    • example.com/api : example.com/api만 허용

<scheme-source>

  • https:와 같은 scheme을 사용할 수 있으며, 콜론(:)이 필수적이다
  • 보안 업그레이드가 허용됨
    • http를 허용하면 https로 로드된 리소스도 허용
    • ws를 허용하면 wss로 로드된 리소스도 허용

upgrade-insecure-requests 지시어

  • 사이트는 때때로 주요 문서를 HTTPS를 통해 제공하지만 리소스는 HTTP를 통해 제공한다. <script src="http://example.org/my-cat.js"></script>

  • 이를 mixed content라고 하며, 안전하지 않은 리소스가 있으면 HTTPS에서 제공하는 보호가 크게 약화된다.
    • 브라우저가 구현하는 mixed content 알고리즘에 따라 문서가 HTTPS를 통해 제공되는 경우 안전하지 않은 리소스는 “업그레이드 가능한 콘텐츠”와 “차단 가능한 콘텐츠”로 분류된다.
  • mixed content에 대한 궁극적인 해결책은 개발자가 모든 리소스를 HTTPS를 통해 로드하는 것입니다.
    • 그러나 사이트가 모든 콘텐츠를 HTTPS를 통해 제공할 수 있더라도 개발자가 리소스를 로드하는 데 사용하는 모든 URL을 다시 작성하는 것은 여전히 매우 어려움 (아카이브된 콘텐츠와 관련된 경우 사실상 불가능할 수도 있음).
  • upgrade-insecure-requests 지시문은 이 문제를 해결하기 위해 사용된다.
    • Content-Security-Policy: upgrade-insecure-requests
  • 이 지시문이 문서에 설정된 경우 브라우저는 다음과 같은 경우 모든 HTTP URL을 HTTPS로 자동 업그레이드한다.
    • 리소스(예: 이미지, 스크립트 등)를 로드하는 요청
    • 문서와 동일한 출처인 탐색 요청(예: 링크 대상)
    • 중첩된 브라우징 컨텍스트의 탐색 요청(예: iframe)
    • form 제출
  • 하지만, 대상이 다른 출처인 최상위 탐색(top-level navigation) 요청은 업그레이드되지 않습니다.
    • Top-level navigation은 브라우저가 현재 페이지에서 다른 페이지로 직접 이동하는 요청을 의미
      • <a href="..."> 링크를 클릭해서 다른 페이지로 이동하거나,
      • 주소창에 URL을 직접 입력해서 이동하거나,
      • 브라우저에서 페이지를 새로고침하거나 다른 웹사이트로 직접 이동하는 등
  • 예를 들어, https://example.org의 문서가 upgrade-insecure-requests 지시어를 포함하는 CSP와 함께 제공되고 해당 문서에 다음과 같은 마크업이 포함되어 있다고 가정했을 때, 브라우저는 두 요청을 모두 자동으로 HTTPS로 업그레이드한다.
    1
    2
    
    <script src="http://example.org/my-cat.js"></script>
    <script src="http://not-example.org/another-cat.js"></script>
    
  • 하지만, 다음의 경우 브라우저는 첫 번째 링크는 HTTPS로 업그레이드하지만, 두 번째 링크는 다른 출처로 이동하기 때문에 업그레이드하지 않는다.
    1
    2
    
    <a href="http://example.org/more-cats">See some more cats!</a>
    <a href="http://not-example.org/even-more-cats">More cats, on another site!</a>
    

CSP로 악의적인 공격 막는 예시

외부 스크립트 주입

  • 예시 : <script src="https://evil.example.com/hacker.js"></script>
  • 방어 : Content-Security-Policy: script-src 'self';
    • 현재 도메인의 스크립트만 허용

인라인 JavaScript 차단

  • 예시
    1
    2
    3
    
    <script>
      console.log("You've been hacked!");
    </script>
    
  • 방어
    • Content-Security-Policy: script-src 'self';
      • <script> 내부의 인라인 JavaScript 실행 차단 ('unsafe-inline’ 키워드가 없으면 인라인 JavaScript 실행 차단됨)

이벤트 핸들러 차단

  • 예시 : <img onmouseover="console.log(You've been hacked!)" />
  • 방어 : Content-Security-Policy: script-src 'self';
    • 위와 마찬가지로 'unsafe-inline'을 제거하면 onmouseover, onclick 같은 인라인 이벤트 핸들러 차단

참고 자료

This post is licensed under CC BY 4.0 by the author.

Hello 2025

iframe이 열리지 않는 이슈 (ancestor violates the following Content Security Policy directive)