참고
이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 10 버전을 참조하세요.
경고
이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조 하세요. 현재 릴리스는 이 문서의 .NET 10 버전을 참조하세요.
이 문서에서는 CSP(콘텐츠 보안 정책)를 ASP.NET Core Blazor 앱과 함께 사용하여 XSS(사이트 간 스크립팅) 및 클릭재킹 공격과 같은 특정 유형의 악의적인 공격으로부터 보호하는 방법을 설명합니다. XSS는 사이버 공격이 하나 이상의 악의적인 클라이언트 쪽 스크립트를 앱의 렌더링된 콘텐츠에 배치하는 보안 취약성입니다. 클릭재킹 공격에서는 사용자가 앱이 포함된 미끼 웹 사이트와 상호 작용하도록 속임을 당합니다.
CSP는 브라우저에 다음과 같은 유효한 정보를 제공하여 이러한 유형의 공격으로부터 보호하는 데 도움이 됩니다.
- 스크립트, 스타일시트, 이미지 및 플러그 인을 포함하여 로드된 콘텐츠의 원본입니다.
- 페이지에 의해 수행된 동작으로, 양식이 허용하는 URL 대상이 명시됩니다.
- 앱이
<frame>,<iframe>,<object>, 또는<embed>태그를 통해 다른 웹 사이트에 포함될 수 있는 경우
CSP를 구현할 때 다음 MDN 리소스를 읽는 것이 좋습니다.
앱에 CSP를 적용하려면 개발자가 하나 이상의 헤더 또는 Content-Security-Policy 태그에 여러 CSP 콘텐츠 보안 ‘지시문’을 지정합니다.<meta> 시작 시 C# 코드의 앱에 CSP를 적용하는 방법에 대한 지침은 ASP.NET Core Blazor 시작 및 이 frame-ancestors 문서의 뒷부분에 있는 지시문 섹션을 참조하세요.
정책은 페이지가 로드되는 동안 브라우저에 의해 평가됩니다. 브라우저가 페이지의 원본을 검사하여 콘텐츠 보안 지시문의 요구 사항을 충족하는지 여부를 확인합니다. 특정 리소스에 대해 정책 지시문이 충족되지 않을 경우 브라우저는 해당 리소스를 로드하지 않습니다. 타사 스크립트를 허용하지 않는 정책을 예로 들면,
<script> 특성에 타사 원본이 있는 src 태그가 페이지에 포함되어 있는 경우 브라우저는 스크립트가 로드되는 것을 차단합니다.
CSP는 Chrome, Edge, Firefox, Opera, Safari를 비롯한 대부분의 최신 데스크톱 및 모바일 브라우저에서 지원됩니다. CSP는 Blazor 앱에서 권장됩니다.
경고
CSP를 구현하면 특정 유형의 보안 위협 위험이 최소화되며 앱이 XSS 및 클릭재킹 공격으로부터 완전히 안전하다고 보장하지는 않습니다. 일반적으로 브라우저인 사용자 에이전트는 사용자가 사용자 기본 설정, 책갈피, 브라우저 확장, 사용자 에이전트에 대한 타사 추가 및 기타 메커니즘을 통해 정책 적용을 수정하거나 바이패스하도록 허용할 수 있습니다. 또한 CSP는 SQL 삽입, CSRF(교차 사이트 요청 위조), 보안 잘못된 구성 및 DoS(서비스 거부) 공격과 같이 보안을 손상시킬 수 있는 모든 공격이 아니라 공격의 하위 집합을 수정하는 데만 초점을 맞습니다.
정책 지시문
다음 지침 및 소스는 일반적으로 앱에서 Blazor 사용됩니다. 필요에 따라 추가 지시문 및 원본을 추가합니다. 다음 지시문은 앱에 대한 보안 정책 예제가 제공되는 이 문서의 섹션에서 사용됩니다.
-
base-uri: 페이지의<base>태그에 대한 URL을 제한합니다. 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면self를 지정합니다. -
default-src: 정책에 의해 명시적으로 지정되지 않은 원본 지시문의 대체를 나타냅니다. 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면self를 지정합니다. -
img-src: 이미지에 대한 유효한 원본을 나타냅니다.-
data:URL에서 이미지가 로드되는 것을 허용하려면data:를 지정합니다. - HTTPS 엔드포인트에서 이미지가 로드되는 것을 허용하려면
https:를 지정합니다.
-
-
object-src:<object>,<embed>및<applet>태그에 대한 유효한 원본을 나타냅니다. 모든 URL 원본을 차단하려면none을 지정합니다. -
script-src: 스크립트에 대한 유효한 원본을 나타냅니다.- 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
self를 지정합니다. - 클라이언트 쪽 Blazor 앱에서:
- 클라이언트 측
wasm-unsafe-evalMono 런타임이 작동하도록 허용하려면 Blazor을(를) 지정합니다. - 필요한 비 프레임워크 스크립트를 로드할 수 있도록 추가 해시를 지정합니다. 예를 들어,
unsafe-hashes에 대한 해시를sha256-qnHnQs7NjQNHHNYv/I9cW+I62HzDJjbnyS/OFzqlix0=으로 지정하여NavMenu구성 요소에서 탐색 토글러의 인라인 JavaScript를 허용합니다.
- 클라이언트 측
- 서버 쪽 Blazor 앱에서 필요한 스크립트를 로드할 수 있도록 해시를 지정합니다.
- 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
-
style-src: 스타일시트에 유효한 원본을 나타냅니다.- 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
self를 지정합니다. - 앱이 인라인 스타일을 사용하는 경우,
unsafe-inline을 지정하여 인라인 스타일을 사용할 수 있도록 합니다.
- 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
-
connect-src: 스크립트 인터페이스를 사용하여 로드할 수 있는 URL을 제한합니다. 스키마 원본http:,ws:(WebSocket 프로토콜) 및wss:(WebSocket Secure 프로토콜)가 지정됩니다. - upgrade-insecure-requests: 안전하지 않은(HTTP) 원본의 콘텐츠 URL을 HTTPS를 통해 안전하게 획득해야 함을 나타냅니다.
-
base-uri: 페이지의<base>태그에 대한 URL을 제한합니다. 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면self를 지정합니다. -
default-src: 정책에 의해 명시적으로 지정되지 않은 원본 지시문의 대체를 나타냅니다. 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면self를 지정합니다. -
img-src: 이미지에 대한 유효한 원본을 나타냅니다.-
data:URL에서 이미지가 로드되는 것을 허용하려면data:를 지정합니다. - HTTPS 엔드포인트에서 이미지가 로드되는 것을 허용하려면
https:를 지정합니다.
-
-
object-src:<object>,<embed>및<applet>태그에 대한 유효한 원본을 나타냅니다. 모든 URL 원본을 차단하려면none을 지정합니다. -
script-src: 스크립트에 대한 유효한 원본을 나타냅니다.- 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
self를 지정합니다. - 클라이언트 쪽 Blazor 앱에서:
- 클라이언트 측
unsafe-evalMono 런타임이 작동하도록 허용하려면 Blazor을(를) 지정합니다. - 필요한 비 프레임워크 스크립트를 로드할 수 있도록 추가 해시를 지정합니다.
- 클라이언트 측
- 서버 쪽 Blazor 앱에서 필요한 스크립트를 로드할 수 있도록 해시를 지정합니다.
- 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
-
style-src: 스타일시트에 유효한 원본을 나타냅니다.- 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
self를 지정합니다. - 앱이 인라인 스타일을 사용하는 경우,
unsafe-inline을 지정하여 인라인 스타일을 사용할 수 있도록 합니다.
- 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
-
connect-src: 스크립트 인터페이스를 사용하여 로드할 수 있는 URL을 제한합니다. 스키마 원본http:,ws:(WebSocket 프로토콜) 및wss:(WebSocket Secure 프로토콜)가 지정됩니다. -
upgrade-insecure-requests: 안전하지 않은(HTTP) 원본의 콘텐츠 URL을 HTTPS를 통해 안전하게 획득해야 함을 나타냅니다.
-
base-uri: 페이지의<base>태그에 대한 URL을 제한합니다. 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면self를 지정합니다. -
default-src: 정책에 의해 명시적으로 지정되지 않은 원본 지시문의 대체를 나타냅니다. 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면self를 지정합니다. -
img-src: 이미지에 대한 유효한 원본을 나타냅니다.-
data:URL에서 이미지가 로드되는 것을 허용하려면data:를 지정합니다. - HTTPS 엔드포인트에서 이미지가 로드되는 것을 허용하려면
https:를 지정합니다.
-
-
object-src:<object>,<embed>및<applet>태그에 대한 유효한 원본을 나타냅니다. 모든 URL 원본을 차단하려면none을 지정합니다. -
script-src: 스크립트에 대한 유효한 원본을 나타냅니다.- 부트스트랩 스크립트의 경우
https://stackpath.bootstrapcdn.com/호스트 원본을 지정합니다. - 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
self를 지정합니다. - 클라이언트 쪽 Blazor 앱에서:
- 클라이언트 측
unsafe-evalMono 런타임이 작동하도록 허용하려면 Blazor을(를) 지정합니다. - 필요한 비 프레임워크 스크립트를 로드할 수 있도록 추가 해시를 지정합니다.
- 클라이언트 측
- 서버 쪽 Blazor 앱에서 필요한 스크립트를 로드할 수 있도록 해시를 지정합니다.
- 부트스트랩 스크립트의 경우
-
style-src: 스타일시트에 유효한 원본을 나타냅니다.- 부트스트랩 스타일시트의 경우
https://stackpath.bootstrapcdn.com/호스트 원본을 지정합니다. - 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
self를 지정합니다. - 인라인 스타일의 사용을 허용하려면
unsafe-inline을 지정합니다.
- 부트스트랩 스타일시트의 경우
-
connect-src: 스크립트 인터페이스를 사용하여 로드할 수 있는 URL을 제한합니다. 스키마 원본http:,ws:(WebSocket 프로토콜) 및wss:(WebSocket Secure 프로토콜)가 지정됩니다. -
upgrade-insecure-requests: 안전하지 않은(HTTP) 원본의 콘텐츠 URL을 HTTPS를 통해 안전하게 획득해야 함을 나타냅니다.
-
base-uri: 페이지의<base>태그에 대한 URL을 제한합니다. 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면self를 지정합니다. -
default-src: 정책에 의해 명시적으로 지정되지 않은 원본 지시문의 대체를 나타냅니다. 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면self를 지정합니다. -
img-src: 이미지에 대한 유효한 원본을 나타냅니다.-
data:URL에서 이미지가 로드되는 것을 허용하려면data:를 지정합니다. - HTTPS 엔드포인트에서 이미지가 로드되는 것을 허용하려면
https:를 지정합니다.
-
-
object-src:<object>,<embed>및<applet>태그에 대한 유효한 원본을 나타냅니다. 모든 URL 원본을 차단하려면none을 지정합니다. -
script-src: 스크립트에 대한 유효한 원본을 나타냅니다.- 부트스트랩 스크립트의 경우
https://stackpath.bootstrapcdn.com/호스트 원본을 지정합니다. - 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
self를 지정합니다. - 클라이언트 쪽 Blazor 앱에서:
- 필요한 스크립트의 로드를 허용하는 해시를 지정합니다.
- 문자열로부터 코드를 만들기 위해
unsafe-eval및 메서드를 사용하려면eval()을 지정합니다.
- 서버 쪽 Blazor 앱에서 필요한 스크립트를 로드할 수 있도록 해시를 지정합니다.
- 부트스트랩 스크립트의 경우
-
style-src: 스타일시트에 유효한 원본을 나타냅니다.- 부트스트랩 스타일시트의 경우
https://stackpath.bootstrapcdn.com/호스트 원본을 지정합니다. - 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면
self를 지정합니다. - 인라인 스타일의 사용을 허용하려면
unsafe-inline을 지정합니다. 초기 요청 후 클라이언트와 서버를 다시 연결하려면 UI에 인라인 선언이 필요합니다. 이후 릴리스에서는unsafe-inline이 더 이상 필요하지 않도록 인라인 스타일이 제거될 수 있습니다.
- 부트스트랩 스타일시트의 경우
-
connect-src: 스크립트 인터페이스를 사용하여 로드할 수 있는 URL을 제한합니다. 스키마 원본http:,ws:(WebSocket 프로토콜) 및wss:(WebSocket Secure 프로토콜)가 지정됩니다. -
upgrade-insecure-requests: 안전하지 않은(HTTP) 원본의 콘텐츠 URL을 HTTPS를 통해 안전하게 획득해야 함을 나타냅니다.
위에 나온 지시문은 Microsoft Internet Explorer를 제외한 모든 브라우저에서 지원됩니다.
추가 인라인 스크립트를 위한 SHA 해시를 획득하려면:
- 정책 적용 섹션에 나와 있는 CSP를 적용합니다.
- 앱을 로컬로 실행하는 상태에서 브라우저의 개발자 도구 콘솔에 액세스합니다. CSP 헤더 또는
meta태그가 있는 경우 브라우저가 차단된 스크립트에 대해 해시를 계산하고 표시합니다. - 브라우저에 표시된 해시를
script-src소스로 복사합니다. 해시 각각을 작은따옴표로 묶으세요.
콘텐츠 보안 정책 수준 2 브라우저 지원 매트릭스를 보려면 Can I use: Content Security Policy Level 2를 참조하세요.
정책 적용
다음을 통해 CSP를 적용할 수 있습니다.
- 호스트에서 발급하거나(예: IIS) 앱에서 발급한 응답 헤더입니다( 시작 시 C# 코드의 컨트롤 헤더 참조).
-
<meta>태그. 이 문서에서는 태그 접근 방식만 보여 줍니다<meta>.
태그를 <meta> 사용하여 정책을 적용하려면:
-
http-equiv특성의 값을Content-Security-Policy로 설정합니다. -
content특성 값에 지시문을 배치합니다. 지시문을 세미콜론(;)으로 구분합니다. 콘텐츠 보안 정책 수준 3 사양에 따라 정책 문자열의 마지막 지시문에 대한 끝 세미콜론이 필요하지 않습니다. -
<meta>태그를 여는<head>태그 바로 안쪽에 에 배치합니다. 정책은 CSP 마크업을 구문 분석할 때 평가되고 적용되므로 모든<head>및<script>태그에 적용되도록 정책이<link>마크업의 상단에 배치하여 표시되어야 합니다.
다음 섹션에서는 예제 정책을 보여줍니다. 이 문서와 함께 각 Blazor 릴리스의 예제는 버전으로 관리됩니다. 릴리스에 적합한 버전을 사용하려면 이 웹 페이지에서 버전 드롭다운 선택기가 있는 문서 버전을 선택합니다.
frame-ancestors 지시문
지시문은 frame-ancestors 페이지를 <frame> 또는 <iframe> 태그로 포함할 수 있는 유효한 부모를 지정합니다.
frame-ancestors 지시문은 <meta> 태그 기반 CSP를 통해 적용할 수 없습니다. 지시문은 응답 헤더에 의해 적용되어야 합니다. 서버 호스트에서 CSP 응답 헤더를 추가하거나 앱 C# 코드에서 지시문으로 frame-ancestors CSP를 추가하거나 업데이트할 수 있습니다.
Blazor Web Apps(.NET 8 이상)에는 값을 'self'다음과 같이 설정하는 응답 헤더가 자동으로 포함됩니다.
Content-Security-Policy: frame-ancestors 'self'
기본값을 더 제한적인 'none'로 변경하고, 모든 부모가 앱을 포함하지 않도록 ContentSecurityFrameAncestorsPolicy 파일의 AddInteractiveServerRenderMode 호출에서 Program 옵션을 설정합니다. 다음은 WebSocket 압축을 사용하도록 설정한 경우에만 적용되며, ConfigureWebSocketAcceptContext가 설정된 상태이고 이는 Blazor 앱의 기본값입니다.
.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")
앱에서, 기본 Blazor Server 지시문은 frame-ancestors 응답 헤더 컬렉션에 추가되지 않습니다. 요청 처리 파이프라인에서 미들웨어 를 사용하여 CSP 헤더를 수동으로 추가할 수 있습니다.
app.Use(async (context, next) =>
{
context.Response.Headers.Add("Content-Security-Policy", "frame-ancestors 'none'");
await next();
});
경고
WebSocket 압축이 활성화된 경우(기본적으로 압축이 사용됨) frame-ancestors 지시문의 값을 'null'로 설정하지 마세요. 이렇게 하면 앱이 악성 스크립트 삽입 및 클릭재킹 공격에 취약해질 수 있습니다.
자세한 내용은 CSP: 프레임 상위 항목(MDN 설명서)을 참조하세요.
서버 쪽 Blazor 앱
다음 예제는 추가 개발을 위한 시작점입니다. 콘텐츠 맨 <head>위에서 정책 지시문 섹션에 설명된 지시문과 앱 사양에 필요한 다른 지시문을 적용합니다.
Blazor Web App 또는 Blazor Server 앱의 경우:
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self' 'wasm-unsafe-eval' 'unsafe-hashes'
'sha256-qnHnQs7NjQNHHNYv/I9cW+I62HzDJjbnyS/OFzqlix0=';
style-src https:;
connect-src 'self' http: ws: wss:;
upgrade-insecure-requests;" />
Blazor Web Apps는 다음 변경 사항 중 하나가 필요한 onclick 구성 요소에 인라인 NavMenu JavaScript 이벤트 처리기를 포함합니다.
script-src키워드를 사용하여unsafe-hashes지시문에 해시를 추가합니다.'unsafe-hashes' 'sha256-qnHnQs7NjQNHHNYv/I9cW+I62HzDJjbnyS/OFzqlix0='자세한 내용은 CSP: script-src: 안전하지 않은 인라인 스크립트(MDN 설명서)를 참조하세요.
인라인 JavaScript 이벤트 처리기를 정책에서 로드할 수 있는 JavaScript 파일 또는 모듈로 이동합니다.
Blazor Web Apps에는 ImportMap 콘텐츠에 <head> 구성 요소가 있으며, 이는 인라인 가져오기 맵 <script> 태그를 렌더링합니다. 정책을 수정하여 가져오기 맵을 로드할 수 있도록 하려면 SRI(하위 리소스 무결성) 또는 암호화된 nonce를 사용하여 CSP 위반 문제 해결 섹션을 참조하세요.
앱의 경우 Blazor Server :
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self';
style-src 'self';
connect-src 'self' http: ws: wss:;
upgrade-insecure-requests">
앱의 경우 Blazor Server :
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self' https://stackpath.bootstrapcdn.com/;
style-src 'self' 'unsafe-inline' https://stackpath.bootstrapcdn.com/;
connect-src 'self' http: ws: wss:;
upgrade-insecure-requests">
앱의 경우 Blazor Server :
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self' https://stackpath.bootstrapcdn.com/
'sha256-34WLX60Tw3aG6hylk0plKbZZFXCuepeQ6Hu7OqRf8PI=';
style-src 'unsafe-inline' https://stackpath.bootstrapcdn.com/;
connect-src 'self' http: ws: wss:;
upgrade-insecure-requests">
참고
위의 SHA256 해시는 데모용입니다. CSP에 대한 새 해시를 계산해야 할 수 있습니다.
앱에 필요한 더 많은 script-src 및 style-src 해시를 추가합니다. 개발하는 동안 온라인 도구나 브라우저 개발자 도구를 사용하여 해시를 계산합니다. 예를 들어 다음 브라우저 도구 콘솔 오류는 정책에서 다루지 않는 필수 스크립트의 해시를 보고합니다.
다음 콘텐츠 보안 정책 지시문을 위반하기 때문에 인라인 스크립트 실행이 거부되었습니다. “ ... ”. 인라인 실행을 사용하려면 ‘unsafe-inline’ 키워드, 해시(‘sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=’) 또는 nonce(‘nonce-...’) 중 하나가 필요합니다.
오류와 관련된 특정 스크립트가 콘솔에서 오류 옆에 표시됩니다.
시작할 때 C# 코드에서 CSP를 앱에 적용하는 방법에 대한 참고 자료는 ASP.NET Core Blazor 시작을 참조하세요.
클라이언트 쪽 Blazor 앱
다음 예제는 추가 개발을 위한 시작점입니다. 콘텐츠<head> 정책 지시문 섹션에 설명된 지시문을 적용합니다.
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self' 'wasm-unsafe-eval';
style-src 'self';
connect-src 'none';
upgrade-insecure-requests">
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self' 'unsafe-eval';
style-src 'self';
connect-src 'none';
upgrade-insecure-requests">
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self' 'unsafe-eval'
'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=';
style-src 'self';
connect-src 'none';
upgrade-insecure-requests">
참고
sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA= 해시는 클라이언트 측 앱에서 사용되는 인라인 스크립트를 나타냅니다. 이 문제는 나중에 제거될 수 있습니다.
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self' 'unsafe-eval' https://stackpath.bootstrapcdn.com/
'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=';
style-src 'self' 'unsafe-inline' https://stackpath.bootstrapcdn.com/;
upgrade-insecure-requests">
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self' 'unsafe-eval' https://stackpath.bootstrapcdn.com/
'sha256-v8ZC9OgMhcnEQ/Me77/R9TlJfzOBqrMTW8e1KuqLaqc='
'sha256-If//FtbPc03afjLezvWHnC3Nbu4fDM04IIzkPaf3pH0='
'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=';
style-src 'self' 'unsafe-inline' https://stackpath.bootstrapcdn.com/;
upgrade-insecure-requests">
앱에 필요한 더 많은 script-src 및 style-src 해시를 추가합니다. 개발하는 동안 온라인 도구나 브라우저 개발자 도구를 사용하여 해시를 계산합니다. 예를 들어 다음 브라우저 도구 콘솔 오류는 정책에서 다루지 않는 필수 스크립트의 해시를 보고합니다.
다음 콘텐츠 보안 정책 지시문을 위반하기 때문에 인라인 스크립트 실행이 거부되었습니다. “ ... ”. 인라인 실행을 사용하려면 ‘unsafe-inline’ 키워드, 해시(‘sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=’) 또는 nonce(‘nonce-...’) 중 하나가 필요합니다.
오류와 관련된 특정 스크립트가 콘솔에서 오류 옆에 표시됩니다.
SRI(하위 리소스 무결성) 또는 암호화된 nonce를 사용하여 CSP 위반 해결
다음 두 섹션에서 설명하는 CSP 위반을 해결하기 위한 두 가지 방법은 다음과 같습니다.
SRI(하위 리소스 무결성) 채택
SRI(하위 리소스 무결성)를 사용하면 브라우저에서 가져온 리소스가 전송 중에 변조되지 않았는지 확인할 수 있습니다. 리소스에 제공된 암호화 해시는 가져온 리소스에 대해 브라우저에서 계산한 해시와 CSP에 나열된 해시와 일치해야 합니다. 브라우저 호환성은 Can I use? Subresource Integrity에서 평가할 수 있습니다.
다음 Blazor Server 앱에 대한 예제에서, 무결성은 타사 도구를 사용하여 계산되고 스크립트(Blazor) 및 CSP에 대해 blazor.server.js 지정됩니다. 이 시나리오에서는 Blazor 스크립트가 동적으로 변경되지 않고 안정적인 SHA 해시가 있으므로 integrity 속성의 값을 하드코딩할 수 있습니다.
경고
crossorigin 없이 다른 원본에서 로드되는 하위 리소스의 특성을 설정합니다. 앱의 원본이 하위 리소스가 로드 Access-Control-Allow-Origin 되는 위치와 다른 경우 리소스를 요청 원본과 공유할 수 있도록 하는 헤더가 필요 하거나, 그렇지 않으면crossorigin 특성이 앱의 하위 리소스 태그에 적용되어야 합니다. 그렇지 않은 경우 브라우저는 하위 리소스에 대한 '장애 조치(fail-open)' 정책을 채택합니다. 즉, 하위 리소스가 무결성을 확인하지 않고 로드됩니다.
crossorigin 특성이 다음 예제의 Blazor<script> 태그에 추가되지 않는 이유는 Blazor 스크립트가 앱의 원본에서 로드되기 때문입니다.
자세한 내용은 원본 간 리소스 공유 및 MDN(하위 리소스 무결성 설명서)을 참조하세요.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'sha256-FyuamsHhg0nWZUnu/f5qrt2DlL1XKt5AX+cgRhtxtfg=';
style-src https:;
connect-src 'self' http: ws: wss:;
upgrade-insecure-requests;" />
...
</head>
<body>
...
<script src="_framework/blazor.server.js"
integrity="sha256-FyuamsHhg0nWZUnu/f5qrt2DlL1XKt5AX+cgRhtxtfg="></script>
</body>
</html>
(.NET 8 이상)에 대한 Blazor Web App 다음 예제에서는 구성 요소(.NET 9 이상)에 대해 ImportMap 무결성을 계산합니다.
ImportMap 구성 요소는 지문 자산에 대해 페이지가 생성될 때마다 고유한 콘텐츠를 렌더링하기 때문에 ImportMap 무결성 값은 각 앱 요청에 대해 계산됩니다.
구성 요소에서 ImportMap 렌더링된 가져오기 맵은 앱의 원본에서 생성되므로 특성이 crossorigin 태그에 ImportMap 포함되지 않습니다. 자세한 내용은 MDN CSP 가이드: 해시 및 MDN(하위 리소스 무결성) 설명서를 참조하세요.
@using System.Security.Cryptography
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self' 'wasm-unsafe-eval' 'unsafe-hashes' '@integrity'
'sha256-qnHnQs7NjQNHHNYv/I9cW+I62HzDJjbnyS/OFzqlix0=';
style-src https:;
connect-src 'self' http: ws: wss:;
upgrade-insecure-requests;" />
...
<ImportMap integrity="@integrity" />
...
</head>
...
</html>
@code {
private string? integrity;
[CascadingParameter]
private HttpContext? HttpContext { get; set; }
protected override void OnInitialized()
{
var metadata = HttpContext?.GetEndpoint()?.Metadata
.GetOrderedMetadata<ImportMapDefinition>();
var utf8 = new System.Text.UTF8Encoding();
var metadataBytes = utf8.GetBytes(
metadata?.FirstOrDefault<ImportMapDefinition>()?.ToString()
.ReplaceLineEndings("\n") ?? string.Empty);
integrity =
$"sha256-{Convert.ToBase64String(SHA256.HashData(metadataBytes))}";
}
}
.NET 6 이전에는 이전 코드에서 .Replace("\r\n", "\n")을(를) 호출하는 대신 ReplaceLineEndings을(를) 사용하세요.
참고
ImportMap 구성 요소의 렌더링된 <script> 요소에 추가 속성을 스플래트해야 하는 경우, ImportMap 속성으로 AdditionalAttributes 구성 요소에 모든 속성의 사전을 전달할 수 있습니다. 키-값 쌍 integrity은 추가로 전달된 나머지 특성과 함께 사전에 전달됩니다.
암호화에 사용되는 단기 유효 비밀번호 채택
암호화 nonce(한 번 사용된 숫자)를 사용하면 브라우저에서 가져온 리소스가 전송 중에 변조되지 않는지 확인할 수 있습니다. CSP에 제공된 일회용 암호 nonce는 리소스에 명시된 nonce와 일치해야 합니다. 브라우저 호환성은 Can I use? Nonce에서 평가할 수 있습니다.
다음 예에서는 (.NET 8 이상) Blazor Web App에 대해 앱이 로드될 때마다 고유한 값이 생성되며, (.NET 9 이상) ImportMap 구성 요소에 대해 nonce가 만들어집니다.
자세한 내용은 MDN CSP 가이드: Nonces 및 CSP: script-src: 안전하지 않은 인라인 스크립트(MDN 설명서)를 참조하세요.
@using System.Security.Cryptography
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Security-Policy" content="
base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self' 'wasm-unsafe-eval' 'unsafe-hashes' 'nonce-@nonce'
'sha256-qnHnQs7NjQNHHNYv/I9cW+I62HzDJjbnyS/OFzqlix0=';
style-src https:;
connect-src 'self' http: ws: wss:;
upgrade-insecure-requests;" />
...
<ImportMap nonce="@nonce" />
...
</head>
...
</html>
@code {
private string? nonce;
protected override void OnInitialized()
{
using (var rng = RandomNumberGenerator.Create())
{
var nonceBytes = new byte[32];
rng.GetBytes(nonceBytes);
nonce = Convert.ToBase64String(nonceBytes);
}
}
}
참고
ImportMap 구성 요소의 렌더링된 <script> 요소에 추가 속성을 스플래트해야 하는 경우, ImportMap 속성으로 AdditionalAttributes 구성 요소에 모든 속성의 사전을 전달할 수 있습니다. nonce 이름-값 쌍은 전달된 추가 특성의 나머지 부분과 함께 데이터 구조 사전에 전달됩니다.
비Development 환경에서 CSP 적용
CSP가 Blazor 앱의 <head> 콘텐츠에 적용될 때 Development 환경에서 로컬 테스트에 방해가 됩니다. 예를 들어 브라우저 링크 및 브라우저 새로 고침 스크립트가 로드되지 않습니다. 다음 예제에서는 비<meta> 환경에서 CSP의 Development 태그를 적용하는 방법을 보여 줍니다.
참고
이 섹션의 예제에서는 CSP에 대한 전체 <meta> 태그를 표시하지 않습니다. 전체 <meta> 태그는 이 문서의 앞부분에 있는 정책 적용 섹션의 하위 섹션에서 찾을 수 있습니다.
세 가지 일반적인 방법을 사용할 수 있습니다.
- 구성 요소를 통해 CSP를
App적용합니다. 이 구성 요소는 앱의 모든 레이아웃에 CSP를 적용합니다. - 앱의 여러 영역에 CSP를 적용해야 하는 경우, 예를 들어 관리자 페이지에만 사용자 지정 CSP를 적용해야 한다면,
<HeadContent>태그를 사용하여 레이아웃 단위로 CSP를 적용합니다. 완전한 효율성을 위해 모든 앱 레이아웃 파일은 접근 방식을 채택해야 합니다. - 호스팅 서비스 또는 서버는 앱의 나가는 응답에 추가된 헤더를 통해 CSP를 제공할 수 있습니다. 이 방법은 서비스 또는 서버를 호스팅하는 방법에 따라 다르므로 다음 예제에서는 다루지 않습니다. 이 방법을 채택하려면 호스팅 서비스 공급자 또는 서버에 대한 설명서를 참조하세요.
Blazor Web App 접근
App 구성 요소(Components/App.razor)에서 IHostEnvironment를 삽입합니다.
@inject IHostEnvironment Env
App 구성 요소의 <head> 콘텐츠에서 Development 환경이 아닌 경우, CSP를 적용합니다.
@if (!Env.IsDevelopment())
{
<meta ...>
}
또는 다음 예제와 같이 폴더의 Components/Layout 레이아웃별로 CSP를 적용합니다. 모든 레이아웃이 CSP를 지정하는지 확인합니다.
@inject IHostEnvironment Env
@if (!Env.IsDevelopment())
{
<HeadContent>
<meta ...>
</HeadContent>
}
Blazor WebAssembly 앱 접근 방식
App 구성 요소(App.razor)에서 IWebAssemblyHostEnvironment를 삽입합니다.
@using Microsoft.AspNetCore.Components.WebAssembly.Hosting
@inject IWebAssemblyHostEnvironment Env
App 구성 요소의 <head> 콘텐츠에서 Development 환경이 아닌 경우, CSP를 적용합니다.
@if (!Env.IsDevelopment())
{
<HeadContent>
<meta ...>
</HeadContent>
}
또는 이전 코드를 사용하되, Layout 폴더에서 레이아웃별로 CSP를 적용합니다. 모든 레이아웃이 CSP를 지정하는지 확인합니다.
Meta 태그 제한 사항
<meta> 태그 정책은 다음 지시문을 지원하지 않습니다.
위의 지시문을 지원하려면 이름이 Content-Security-Policy인 헤더를 사용하세요. 지시문 문자열은 헤더의 값입니다.
정책 테스트 및 위반 보고서 받기
테스트를 사용하면 초기 정책을 빌드할 때 타사 스크립트가 실수로 차단되지 않는지 확인할 수 있습니다.
정책 지시문을 적용하지 않고 일정 시간 동안 정책을 테스트하려면 <meta> 태그의 http-equiv 특성이나 헤더 기반 정책의 헤더 이름을 Content-Security-Policy-Report-Only로 설정합니다. 오류 보고서는 지정된 URL로 JSON 문서로 전송됩니다. 자세한 내용은 MDN 웹 문서: Content-Security-Policy-Report-Only를 참조하세요.
정책이 활성 상태일 때의 위반 보고에 대해 알아보려면 다음 문서를 참조하세요.
report-uri는 더 이상 사용하지 않는 것이 좋지만 모든 주요 브라우저에서 report-to가 지원될 때까지 두 지시문을 모두 사용해야 합니다.
report-uri에 대한 지원은 브라우저에서 ‘언제든지’ 제거될 수 있으므로 report-uri만 단독으로 사용하지 마세요.
report-uri가 완전히 지원되는 시점에 정책에서 report-to에 대한 지원을 제거하세요.
report-to의 채택 여부를 추적하려면 Can I use: report-to(report-to를 사용해도 될까요?)를 참조하세요.
릴리스마다 앱의 정책을 테스트하고 업데이트하시기 바랍니다.
문제 해결
- 오류는 브라우저의 개발자 도구 콘솔에 표시됩니다. 브라우저는 다음 사항에 대한 정보를 제공합니다.
- 정책을 준수하지 않는 요소.
- 차단된 항목을 허용하도록 정책을 수정하는 방법.
- 정책은 클라이언트의 브라우저에서 포함된 모든 지시문을 지원하는 경우에만 완전히 유효합니다. 현재 브라우저 지원 매트릭스는 Can I use: Content-Security-Policy를 참조하세요.
추가 리소스
ASP.NET Core