콘텐츠 보안 정책(CSP)이 교차 사이트 스크립팅(XSS) 공격을 효과적으로 완화하여 전 세계 사용자들을 위한 웹 보안을 강화하는 방법을 알아보세요.
콘텐츠 보안 정책 (CSP): XSS 방지를 위한 종합 가이드
오늘날의 디지털 환경에서 웹 보안은 매우 중요합니다. 교차 사이트 스크립팅(XSS) 공격은 전 세계 웹 애플리케이션에 만연하고 위험한 위협으로 남아 있습니다. 콘텐츠 보안 정책(CSP)은 XSS 취약점의 위험을 완화하는 데 도움이 되는 추가 보안 계층을 제공하는 강력한 HTTP 응답 헤더입니다. 이 가이드는 CSP, 구현 방법, 그리고 XSS 공격으로부터 웹 애플리케이션을 보호하기 위한 모범 사례에 대한 포괄적인 개요를 제공합니다.
교차 사이트 스크립팅(XSS)이란 무엇인가요?
교차 사이트 스크립팅(XSS)은 악성 스크립트가 선의의 신뢰할 수 있는 웹사이트에 주입되는 일종의 삽입 공격입니다. XSS 공격은 공격자가 웹 애플리케이션을 사용하여 일반적으로 브라우저 측 스크립트 형태의 악성 코드를 다른 최종 사용자에게 전송할 때 발생합니다. 이러한 공격을 성공하게 하는 결함은 매우 광범위하며, 웹 애플리케이션이 사용자의 입력을 유효성 검사 또는 인코딩 없이 생성하는 출력에 사용할 때마다 발생합니다.
XSS 공격에는 크게 세 가지 유형이 있습니다:
- 저장형(지속형) XSS: 악성 스크립트가 대상 서버(예: 데이터베이스, 메시지 포럼, 방문자 로그, 댓글 필드 등)에 영구적으로 저장됩니다. 사용자가 영향을 받는 페이지를 방문하면 저장된 스크립트가 실행됩니다.
- 반사형(비지속형) XSS: 악성 스크립트가 웹 서버로부터 반사되어 나타나는 형태입니다. 예를 들어, 오류 메시지, 검색 결과 또는 서버로 전송된 입력의 일부 또는 전부를 포함하는 기타 응답에 나타날 수 있습니다. 사용자는 악성 링크를 클릭하거나 악성 스크립트가 포함된 양식을 제출하도록 유도되어야 합니다.
- DOM 기반 XSS: 취약점이 클라이언트 측 코드 자체에 존재합니다. 브라우저의 DOM 환경이 조작되어 공격자의 스크립트를 포함하게 되면서 악성 스크립트가 실행됩니다.
XSS 공격은 다음과 같은 심각한 결과를 초래할 수 있습니다:
- 사용자 인증 정보(쿠키, 세션 토큰) 도용.
- 웹사이트 변조.
- 사용자를 악성 사이트로 리디렉션.
- 멀웨어 설치.
- 민감한 데이터에 대한 무단 액세스 획득.
콘텐츠 보안 정책(CSP)이란 무엇인가요?
콘텐츠 보안 정책(CSP)은 교차 사이트 스크립팅(XSS) 및 데이터 삽입 공격을 포함한 특정 유형의 공격을 탐지하고 완화하는 데 도움이 되는 추가 보안 계층입니다. CSP는 브라우저가 특정 페이지에 대해 로드할 수 있는 리소스(예: 스크립트, 스타일시트, 이미지, 글꼴, 프레임)를 제어할 수 있도록 하는 HTTP 응답 헤더를 사용하여 구현됩니다. 엄격한 CSP를 정의함으로써 웹 애플리케이션의 공격 노출 영역을 크게 줄이고 공격자가 악성 코드를 삽입하기 어렵게 만들 수 있습니다.
CSP는 브라우저가 리소스를 로드할 수 있도록 허용된 소스의 화이트리스트를 정의하여 작동합니다. CSP에서 명시적으로 허용되지 않은 소스에서 로드된 모든 리소스는 브라우저에 의해 차단됩니다. 이는 승인되지 않은 스크립트의 실행을 방지하고 XSS 공격의 위험을 줄입니다.
CSP 작동 방식: 디렉티브 및 소스
CSP는 일련의 디렉티브를 사용하여 구성되며, 각 디렉티브는 특정 유형의 리소스에 대한 정책을 지정합니다. 각 디렉티브는 이름과 허용된 소스 목록으로 구성됩니다. 다음은 가장 일반적으로 사용되는 CSP 디렉티브 중 일부입니다:
- `default-src`: 다른 리소스별 디렉티브가 없는 경우 리소스 가져오기에 대한 기본 정책을 지정합니다.
- `script-src`: 자바스크립트 코드에 허용되는 소스를 지정합니다.
- `style-src`: 스타일시트(CSS)에 허용되는 소스를 지정합니다.
- `img-src`: 이미지에 허용되는 소스를 지정합니다.
- `font-src`: 글꼴에 허용되는 소스를 지정합니다.
- `connect-src`: 네트워크 요청(예: AJAX, WebSockets)을 만드는 데 허용되는 소스를 지정합니다.
- `media-src`: 비디오 및 오디오 리소스를 로드하는 데 허용되는 소스를 지정합니다.
- `object-src`: Flash와 같은 플러그인에 허용되는 소스를 지정합니다.
- `frame-src`: 프레임(iframe) 임베딩에 허용되는 소스를 지정합니다.
- `base-uri`: 문서의 <base> 요소에 사용될 수 있는 URL을 제한합니다.
- `form-action`: 양식이 제출될 수 있는 URL을 제한합니다.
- `upgrade-insecure-requests`: 브라우저가 안전하지 않은(HTTP) 요청을 안전한(HTTPS) 요청으로 자동 업그레이드하도록 지시합니다.
- `block-all-mixed-content`: 페이지가 HTTPS를 통해 로드될 때 브라우저가 HTTP를 사용하여 리소스를 로드하는 것을 방지합니다.
- `report-uri`: 브라우저가 CSP 위반 보고서를 보낼 URL을 지정합니다. `report-to`로 대체되어 더 이상 사용되지 않습니다.
- `report-to`: 브라우저가 CSP 위반 보고서를 보낼 명명된 엔드포인트를 지정합니다.
일반적으로 사용되는 소스 값은 다음과 같습니다:
- `*`: 모든 소스에서 리소스를 허용합니다 (프로덕션 환경에서는 권장되지 않음).
- `'self'`: 보호되는 문서와 동일한 출처(스키마, 호스트, 포트)에서 리소스를 허용합니다.
- `'none'`: 어떤 소스에서도 리소스 로드를 허용하지 않습니다.
- `data:`: `data:` 스키마를 통한 리소스 로드를 허용합니다 (예: 인라인 이미지).
- `'unsafe-inline'`: 인라인 자바스크립트 및 CSS 사용을 허용합니다 (강력히 권장되지 않음).
- `'unsafe-eval'`: `eval()` 및 유사 함수의 사용을 허용합니다 (강력히 권장되지 않음).
- `'strict-dynamic'`: 마크업에 존재하는 스크립트에 nonce 또는 해시를 함께 사용하여 명시적으로 부여된 신뢰가 해당 루트 스크립트에 의해 로드된 모든 스크립트로 전파되도록 지정합니다.
- `'nonce-
'` : 일치하는 nonce 속성을 가진 스크립트 또는 스타일을 허용합니다. - `'sha256-
'`, `'sha384- : 일치하는 SHA 해시를 가진 스크립트 또는 스타일을 허용합니다.'`, `'sha512- '` - `https://example.com`: 특정 도메인에서 리소스를 허용합니다.
CSP 구현
CSP는 두 가지 주요 방식으로 구현될 수 있습니다:
- HTTP 헤더: 선호되는 방법은 웹 서버가 `Content-Security-Policy` HTTP 응답 헤더를 보내도록 구성하는 것입니다. 이를 통해 웹사이트의 각 페이지 또는 리소스에 대한 CSP를 정의할 수 있습니다.
- <meta> 태그: CSP는 HTML 문서의 <head> 섹션에 <meta> 태그를 사용하여 정의할 수도 있습니다. 그러나 이 방법은 HTTP 헤더를 사용하는 것에 비해 유연성이 떨어지고 제한 사항이 있습니다. 예를 들어, `frame-ancestors`, `sandbox`, `report-uri` 디렉티브는 HTML 메타 태그에서 사용할 수 없습니다.
HTTP 헤더 사용
HTTP 헤더를 사용하여 CSP를 구현하려면 웹 서버가 응답에 `Content-Security-Policy` 헤더를 포함하도록 구성해야 합니다. 특정 구성 단계는 사용 중인 웹 서버에 따라 달라집니다.
다음은 일반적인 웹 서버에 대한 예시입니다:
- Apache: `.htaccess` 파일 또는 가상 호스트 구성에 다음 줄을 추가합니다:
Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://example.com; style-src 'self' https://example.com; img-src 'self' data:;"
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://example.com; style-src 'self' https://example.com; img-src 'self' data:;";
app.use(function(req, res, next) {
res.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self' https://example.com; style-src 'self' https://example.com; img-src 'self' data:;");
next();
});
<meta> 태그 사용
<meta> 태그를 사용하여 CSP를 구현하려면 HTML 문서의 <head> 섹션에 다음 태그를 추가합니다:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://example.com; style-src 'self' https://example.com; img-src 'self' data:;">
중요 고려 사항:
- `http-equiv` 속성은 "Content-Security-Policy"로 설정되어야 합니다.
- `content` 속성에는 CSP 디렉티브가 포함됩니다.
- 앞서 언급된 <meta> 태그 사용의 제한 사항을 기억하십시오.
CSP 예시
다음은 설명과 함께 제공되는 몇 가지 CSP 예시입니다:
- 기본 CSP:
- 특정 도메인의 스크립트 허용:
- CDN의 스타일 허용:
- 모든 소스의 이미지 허용:
- CSP 위반 보고:
- 호환성을 위해 `report-to`와 `report-uri` 함께 사용:
- 인라인 스크립트에 Nonce 사용:
Content-Security-Policy: default-src 'self';
이 정책은 동일한 출처의 리소스만 허용합니다.
Content-Security-Policy: default-src 'self'; script-src 'self' https://example.com;
이 정책은 동일한 출처의 리소스와 `https://example.com`의 스크립트를 허용합니다.
Content-Security-Policy: default-src 'self'; style-src 'self' https://cdn.example.com;
이 정책은 동일한 출처의 리소스와 `https://cdn.example.com`의 스타일을 허용합니다.
Content-Security-Policy: default-src 'self'; img-src *;
이 정책은 동일한 출처의 리소스와 모든 소스의 이미지를 허용합니다 (프로덕션 환경에서는 권장되지 않음).
Content-Security-Policy: default-src 'self'; report-uri /csp-report-endpoint;
이 정책은 동일한 출처의 리소스를 허용하고 위반 보고서를 `/csp-report-endpoint`로 보냅니다. `report-uri` 대신 `report-to`를 사용하는 것이 권장됩니다.
Content-Security-Policy: default-src 'self'; report-uri /csp-report-endpoint; report-to csp-endpoint;
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint; report-to csp-endpoint;
Report-To: {\"group\":\"csp-endpoint\",\"max_age\":10886400,\"endpoints\":[{\"url\":\"/csp-report-endpoint\"}]}
이 예시는 `report-uri`(이전 브라우저용)와 `report-to` 엔드포인트를 모두 설정하고, `Report-To` 헤더 자체를 구성하는 방법을 보여줍니다. 서버가 `Report-To` 헤더를 올바르게 처리하여 `group`, `max_age`, `endpoints`를 올바르게 설정하는지 확인하십시오.
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-rAnd0mN0nc3Str1nG';
이 정책은 동일한 출처의 리소스와 일치하는 nonce 속성을 가진 인라인 스크립트를 허용합니다.
<script nonce=\"rAnd0mN0nc3Str1nG\">
// 여기에 인라인 스크립트 코드
</script>
보고 전용 모드의 CSP
CSP는 두 가지 모드로 구현될 수 있습니다:
- 강제 모드: 브라우저가 CSP를 위반하는 리소스를 차단합니다.
- 보고 전용 모드: 브라우저가 리소스를 차단하지 않고 CSP 위반을 지정된 엔드포인트로 보고합니다.
보고 전용 모드는 CSP를 강제하기 전에 테스트하고 개선하는 데 유용합니다. 보고 전용 모드를 활성화하려면 `Content-Security-Policy` 헤더 대신 `Content-Security-Policy-Report-Only` HTTP 헤더를 사용합니다.
예시:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint;
이 구성은 리소스를 차단하지 않고 `/csp-report-endpoint`로 보고서를 보낼 것입니다.
CSP 구현 모범 사례
다음은 CSP를 효과적으로 구현하기 위한 몇 가지 모범 사례입니다:
- 엄격한 정책으로 시작하기: 동일한 출처의 리소스만 허용하는 제한적인 정책으로 시작하여 필요에 따라 점진적으로 완화하십시오.
- 인라인 스크립트 및 스타일에 Nonce 또는 해시 사용: `'unsafe-inline'` 사용을 피하고 nonce 또는 해시를 사용하여 특정 인라인 스크립트 및 스타일을 허용하십시오.
- `'unsafe-eval'` 피하기: 가능하다면 보안 위험을 초래할 수 있으므로 `'unsafe-eval'` 사용을 피하십시오. 동적 코드 실행을 위한 대체 접근 방식을 고려하십시오.
- HTTPS 사용: 중간자 공격을 방지하기 위해 모든 리소스가 HTTPS를 통해 로드되도록 하십시오. `upgrade-insecure-requests` 디렉티브를 사용하여 안전하지 않은 요청을 자동으로 업그레이드하십시오.
- CSP 위반 모니터링: CSP 위반을 모니터링하고 잠재적인 보안 문제를 식별하기 위한 보고 엔드포인트를 설정하십시오.
- CSP 철저히 테스트: CSP가 예상대로 작동하는지 확인하기 위해 다양한 브라우저 및 환경에서 CSP를 테스트하십시오.
- 반복 및 개선: CSP 구현은 반복적인 프로세스입니다. 애플리케이션이 진화함에 따라 CSP를 지속적으로 모니터링하고 개선하십시오.
- `strict-dynamic` 디렉티브 고려: `strict-dynamic`을 사용하여 신뢰할 수 있는 스크립트에 의해 로드된 스크립트로 신뢰를 전파함으로써 CSP의 복잡성을 줄이십시오.
CSP 도구
CSP를 생성, 테스트 및 모니터링하는 데 도움이 되는 몇 가지 도구가 있습니다:
- CSP 생성기: 웹사이트의 리소스를 기반으로 CSP 디렉티브를 생성하는 온라인 도구입니다.
- 브라우저 개발자 도구: 대부분의 최신 브라우저는 CSP 위반을 분석하는 데 도움이 되는 개발자 도구를 제공합니다.
- CSP 모니터링 서비스: CSP 위반 보고서를 수집하고 분석하는 서비스입니다.
CSP와 프레임워크/라이브러리
프레임워크 및 라이브러리를 사용할 때 호환성을 보장하고 보안 문제를 방지하려면 CSP를 올바르게 구성하는 것이 중요합니다. 다음은 몇 가지 고려 사항입니다:
- 자바스크립트 프레임워크(예: React, Angular, Vue.js): 이러한 프레임워크는 종종 인라인 스타일 또는 동적 코드 생성을 사용하므로 특별한 CSP 구성(예: nonce, 해시, `'unsafe-eval'`)이 필요할 수 있습니다.
- CSS 프레임워크(예: Bootstrap, Tailwind CSS): 이러한 프레임워크는 인라인 스타일 또는 외부 스타일시트를 사용할 수 있으며, 이는 CSP에서 허용되어야 합니다.
- 타사 라이브러리: 사용하는 모든 타사 라이브러리가 CSP와 호환되고 보안 취약점을 유발하지 않는지 확인하십시오.
CSP와 CDN(콘텐츠 전송 네트워크)
CDN은 자바스크립트 파일, CSS 스타일시트 및 이미지와 같은 정적 자산을 호스팅하는 데 일반적으로 사용됩니다. CSP에서 CDN의 리소스를 허용하려면 CDN 도메인을 명시적으로 화이트리스트에 추가해야 합니다.
예시:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; style-src 'self' https://cdnjs.cloudflare.com;
이 정책은 jsDelivr의 스크립트와 Cloudflare의 cdnjs의 스타일을 허용합니다.
피해야 할 일반적인 CSP 실수
다음은 피해야 할 일반적인 CSP 실수입니다:
- `*`를 소스로 사용: 모든 소스에서 리소스를 허용하면 CSP의 이점이 상쇄될 수 있습니다.
- 정당한 이유 없이 `'unsafe-inline'` 및 `'unsafe-eval'` 사용: 이러한 디렉티브는 보안 위험을 초래할 수 있으므로 가능하면 피해야 합니다.
- CSP 위반을 모니터링하지 않음: CSP 위반을 모니터링하지 않으면 보안 문제를 식별하고 해결할 수 없습니다.
- CSP를 철저히 테스트하지 않음: 불충분한 테스트는 예기치 않은 동작과 보안 취약점으로 이어질 수 있습니다.
- Nonce 및 해시 잘못 구성: 잘못 구성된 nonce 및 해시는 합법적인 스크립트와 스타일이 로드되는 것을 방해할 수 있습니다.
고급 CSP 개념
기본 사항 외에도 웹 보안을 더욱 강화할 수 있는 몇 가지 고급 CSP 개념이 있습니다:
- `frame-ancestors` 디렉티브: 페이지에 프레임(iframe)을 임베드할 수 있는 허용된 부모를 지정합니다. 클릭재킹 공격으로부터 보호합니다.
- `sandbox` 디렉티브: 요청된 리소스에 대한 샌드박스를 활성화하고 해당 기능에 제한을 적용합니다(예: 스크립트 실행, 양식 제출 방지).
- `require-sri-for` 디렉티브: 외부 소스에서 로드된 스크립트 또는 스타일에 대해 하위 리소스 무결성(SRI)을 요구합니다. SRI는 파일이 변조되지 않았는지 확인합니다.
- Trusted Types API: DOM 싱크에 대한 타입 안전성을 적용하여 DOM 기반 XSS를 방지하는 데 도움이 됩니다.
CSP의 미래
CSP는 새로운 보안 문제에 대응하기 위해 끊임없이 진화하고 있습니다. 향후 개발은 다음과 같을 수 있습니다:
- 향상된 브라우저 지원: CSP 기능에 대한 브라우저 지원의 지속적인 개선.
- 새로운 디렉티브 및 기능: 새로운 보안 위협에 대응하기 위한 새로운 디렉티브 및 기능 도입.
- 보안 도구와의 통합: CSP 관리 및 모니터링 자동화를 위한 보안 도구 및 플랫폼과의 심층 통합.
결론
콘텐츠 보안 정책(CSP)은 XSS 공격을 완화하고 웹 보안을 강화하는 강력한 도구입니다. 엄격한 CSP를 정의함으로써 웹 애플리케이션의 공격 노출 영역을 크게 줄이고 악성 코드로부터 사용자를 보호할 수 있습니다. CSP를 효과적으로 구현하려면 신중한 계획, 철저한 테스트, 지속적인 모니터링이 필요합니다. 이 가이드에 설명된 모범 사례를 따르면 CSP를 활용하여 웹 애플리케이션의 보안 상태를 개선하고 글로벌 디지털 생태계에서 온라인 입지를 보호할 수 있습니다.
진화하는 보안 위협에 적응하고 웹 애플리케이션이 계속 보호되도록 CSP를 정기적으로 검토하고 업데이트하는 것을 잊지 마십시오.