본문 바로가기
IT/web

Content Security Policy

by 내일은교양왕 2023. 7. 16.

Content Security Policy(CSP)는 웹 애플리케이션에서 교차 사이트 스크립팅(XSS)이나 데이터 인젝션 공격을 방지하기 위한 보안 기능입니다. 개발자가 애플리케이션에서 허용하는 리소스의 출처를 명시적으로 선언함으로써, 악의적인 코드 실행을 막을 수 있게 해줍니다.


📌 핵심 개념 요약

  • 무엇인가?
    CSP는 브라우저에 특정 콘텐츠(스크립트, 스타일, 이미지 등)를 어디서 로드할 수 있는지 알려주는 보안 정책입니다.
  • 왜 필요한가?
    악성 스크립트나 외부 리소스가 웹 페이지에 삽입되어 실행되는 것을 막기 위함입니다.
  • 어떻게 동작하는가?
    서버가 HTTP 응답 헤더(Content-Security-Policy) 또는 <meta> 태그를 통해 정책을 명시하면, 브라우저가 그 정책을 기준으로 콘텐츠 로드를 제한합니다.

🧩 예시

Content-Security-Policy: default-src 'self'; img-src *; script-src 'self' https://apis.example.com
  • default-src 'self': 기본적으로 현재 출처(origin)에서만 리소스를 로드함
  • img-src *: 이미지 리소스는 어디에서든 허용
  • script-src 'self' https://apis.example.com: 스크립트는 현재 출처와 특정 외부 API만 허용

🔐 방어 가능한 공격

  • XSS(교차 사이트 스크립팅)
  • clickjacking
  • 악성 iframe 삽입
  • 데이터 인젝션

⚠️ 주의점

  • CSP를 너무 강하게 설정하면 정상적인 콘텐츠도 차단될 수 있음
  • 기존 코드에 inline script나 eval()이 많다면 많은 수정이 필요함

 

 

1. CSP 설정 방법

CSP는 HTTP 응답 헤더 또는 <meta> 태그로 설정할 수 있어.

방법 A: HTTP 응답 헤더로 설정 (권장)

서버 설정 또는 백엔드 코드에서 아래처럼 설정:

Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com

💡 예: Express.js (Node.js 서버)

app.use((req, res, next) => {
  res.setHeader(
    "Content-Security-Policy",
    "default-src 'self'; script-src 'self' https://cdn.example.com"
  );
  next();
});

방법 B: HTML <meta> 태그로 설정 (서버 접근 어려울 때)

※ 단, meta 태그는 일부 정책을 완벽히 지원하지 않으므로 가능하면 헤더 방식이 좋아.

 

2. 적용 예제

예시 상황:

내 사이트는 다음과 같은 리소스를 사용함

  • HTML, JS, CSS는 모두 내 도메인에서 제공
  • 외부 CDN(jsDelivr)에서 일부 스크립트를 사용
  • 이미지 출처는 어디든 상관없음
  • 인라인 스크립트는 금지하고 싶음

CSP 정책 예시:

Content-Security-Policy: 
  default-src 'self'; 
  script-src 'self' https://cdn.jsdelivr.net; 
  img-src *; 
  style-src 'self'; 
  object-src 'none';

설명:

지시어 의미

default-src 'self' 기본 리소스 출처는 자기 자신만 허용
script-src 'self' https://cdn.jsdelivr.net js는 내 도메인과 jsDelivr만 허용
img-src * 이미지는 어디서든 로드 가능
style-src 'self' CSS는 내 도메인만 허용
object-src 'none' 플러그인, Flash 등은 모두 차단

 3. 디버깅 및 테스트 방법

  1. 브라우저 개발자도구(F12) → "콘솔" 탭에서 차단된 리소스 확인
  2. Content-Security-Policy-Report-Only 헤더로 테스트 가능→ 실제로 차단은 안 하고 위반 사항만 브라우저에 로깅함
  3. Content-Security-Policy-Report-Only: ...

 4. 개발 팁

  • script-src에서 'unsafe-inline', 'unsafe-eval' 같은 위험한 설정은 피하기
  • CSP 테스트 도구:
    https://csp-evaluator.withgoogle.com/ (Google에서 제공)
  • React, Vue 등 SPA는 style-src, script-src 설정에 주의

 

SPA(Single Page Application)**에서 style-src와 script-src 설정에 주의해야 하는 이유

런 프레임워크들이 런타임에 동적으로 코드를 생성하거나 적용하는 경우가 많기 때문이야. 구체적으로 설명해줄게

script-src 주의 이유

1. React, Vue의 번들 스크립트는 외부에서 로드될 수 있음

  • 예: https://cdn.example.com/main.js
  • CSP에서 이 출처를 명시하지 않으면 브라우저가 스크립트를 차단해버림.
  • 특히 외부 CDN을 사용하는 경우 꼭 출처를 추가해야 함.
script-src 'self' https://cdn.example.com

2. 인라인 스크립트가 기본적으로 차단됨

  • CSP는 script-src에서 'unsafe-inline'이 없으면 <script>alert(1)</script> 같은 인라인 스크립트를 차단함.
  • Vue, React 앱에 <script> 안에 직접 코드를 넣었다면 문제 발생 가능.
  • 대부분의 SPA는 빌드 도구(Webpack 등)로 외부 파일로 번들링하기 때문에 인라인 스크립트를 안 쓰도록 설계되어야 함.

style-src 주의 이유

1. 인라인 스타일 사용이 차단될 수 있음

  • Vue나 React에서 style={{ color: 'red' }} 같은 **인라인 스타일(JSX 방식)**은 CSP에서 'unsafe-inline'을 허용하지 않으면 적용되지 않을 수 있어.

2. CSS-in-JS 라이브러리 문제

  • styled-components, Emotion 같은 라이브러리는 런타임에 스타일 태그를 동적으로 생성해서 DOM에 삽입함.
  • 이 경우 CSP는 nonce 또는 hash 기반 정책이 필요함. 안 그러면 동적 스타일이 차단됨.

해결 방법 요약

상황 해결 방법

외부 CDN에서 script 로드 script-src에 출처 명시
JSX의 인라인 스타일 사용 'unsafe-inline' 또는 nonce/hash 방식 고려
styled-components 등 사용 nonce 설정 또는 'unsafe-inline' 임시 허용
<script>에 직접 코드 삽입 사용 자제하거나 'unsafe-inline' 허용

실전 팁

React 앱에 안전한 CSP 적용 예시:

Content-Security-Policy: 
  default-src 'self'; 
  script-src 'self' https://cdn.example.com; 
  style-src 'self' 'unsafe-inline'; 
  object-src 'none';

'unsafe-inline'은 보안상 위험하므로, 가능하면 nonce 방식을 사용하는 걸 추천해!