ASP.NET Core Blazor에 콘텐츠 보안 정책 적용

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

이 문서에서는 ASP.NET Core Blazor 앱에 CSP(콘텐츠 보안 정책)를 사용하여 XSS(교차 사이트 스크립팅) 공격으로부터 보호하는 방법을 설명합니다.

XSS(교차 사이트 스크립팅)는 공격자가 앱의 렌더링된 콘텐츠에 하나 이상의 악성 클라이언트 쪽 스크립트를 배치하는 보안 취약성입니다. CSP는 브라우저에 다음을 알림으로써 XSS 공격을 막아내는 데 도움을 줍니다.

  • 스크립트, 스타일시트, 이미지 및 플러그 인을 포함하여 로드된 콘텐츠의 원본입니다.
  • 페이지에 의해 취해진 유효한 동작(양식의 허용되는 URL 대상 지정)

앱에 CSP를 적용하려면 개발자가 하나 이상의 Content-Security-Policy 헤더 또는 <meta> 태그에 여러 CSP 콘텐츠 보안 ‘지시문’을 지정합니다. 시작할 때 C# 코드에서 CSP를 앱에 적용하는 방법에 대한 참고 자료는 ASP.NET Core Blazor 시작을 참조하세요.

정책은 페이지가 로드되는 동안 브라우저에 의해 평가됩니다. 브라우저가 페이지의 원본을 검사하여 콘텐츠 보안 지시문의 요구 사항을 충족하는지 여부를 확인합니다. 특정 리소스에 대해 정책 지시문이 충족되지 않을 경우 브라우저는 해당 리소스를 로드하지 않습니다. 타사 스크립트를 허용하지 않는 정책을 예로 들면, src 특성에 타사 원본이 있는 <script> 태그가 페이지에 포함되어 있는 경우 브라우저는 스크립트가 로드되는 것을 차단합니다.

CSP는 Chrome, Edge, Firefox, Opera, Safari를 비롯한 대부분의 최신 데스크톱 및 모바일 브라우저에서 지원됩니다. CSP는 Blazor 앱에서 권장됩니다.

정책 지시문

최소한 Blazor 앱에 대해 다음 지시문 및 원본을 지정합니다. 필요에 따라 추가 지시문 및 원본을 추가합니다. 다음 지시문은 앱에 대한 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 앱에서:
      • 클라이언트 쪽 Blazor Mono 런타임이 작동하도록 허용하도록 지정 wasm-unsafe-eval 합니다.
      • 필요한 비 프레임워크 스크립트를 로드할 수 있도록 추가 해시를 지정합니다.
    • 서버 쪽 Blazor 앱에서 필요한 스크립트를 로드할 수 있도록 해시를 지정합니다.
  • style-src: 스타일시트에 유효한 원본을 나타냅니다.
    • 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면 self를 지정합니다.
    • 앱이 인라인 스타일을 사용하는 경우 unsafe-inline을 지정하여 인라인 스타일을 사용합니다.
  • 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 앱에서:
      • 클라이언트 쪽 Blazor Mono 런타임이 작동하도록 허용하도록 지정 unsafe-eval 합니다.
      • 필요한 비 프레임워크 스크립트를 로드할 수 있도록 추가 해시를 지정합니다.
    • 서버 쪽 Blazor 앱에서 필요한 스크립트를 로드할 수 있도록 해시를 지정합니다.
  • style-src: 스타일시트에 유효한 원본을 나타냅니다.
    • 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면 self를 지정합니다.
    • 앱이 인라인 스타일을 사용하는 경우 unsafe-inline을 지정하여 인라인 스타일을 사용합니다.
  • 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 앱에서:
      • 클라이언트 쪽 Blazor Mono 런타임이 작동하도록 허용하도록 지정 unsafe-eval 합니다.
      • 필요한 비 프레임워크 스크립트를 로드할 수 있도록 추가 해시를 지정합니다.
    • 서버 쪽 Blazor 앱에서 필요한 스크립트를 로드할 수 있도록 해시를 지정합니다.
  • style-src: 스타일시트에 유효한 원본을 나타냅니다.
    • 부트스트랩 스타일시트의 경우 https://stackpath.bootstrapcdn.com/ 호스트 원본을 지정합니다.
    • 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면 self를 지정합니다.
    • 인라인 스타일의 사용을 허용하려면 unsafe-inline을 지정합니다.
  • 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 앱에서:
      • 필요한 스크립트의 로드를 허용하는 해시를 지정합니다.
      • 문자열로부터 코드를 만들기 위해 eval() 및 메서드를 사용하려면 unsafe-eval을 지정합니다.
    • 서버 쪽 Blazor 앱에서 필요한 스크립트를 로드할 수 있도록 해시를 지정합니다.
  • style-src: 스타일시트에 유효한 원본을 나타냅니다.
    • 부트스트랩 스타일시트의 경우 https://stackpath.bootstrapcdn.com/ 호스트 원본을 지정합니다.
    • 체계 및 포트 번호를 포함하여 앱의 원본이 유효한 원본임을 나타내려면 self를 지정합니다.
    • 인라인 스타일의 사용을 허용하려면 unsafe-inline을 지정합니다. 초기 요청 후 클라이언트와 서버를 다시 연결하려면 UI에 인라인 선언이 필요합니다. 이후 릴리스에서는 unsafe-inline이 더 이상 필요하지 않도록 인라인 스타일이 제거될 수 있습니다.
  • upgrade-insecure-requests: 안전하지 않은(HTTP) 원본의 콘텐츠 URL을 HTTPS를 통해 안전하게 획득해야 함을 나타냅니다.

위에 나온 지시문은 Microsoft Internet Explorer를 제외한 모든 브라우저에서 지원됩니다.

추가 인라인 스크립트를 위한 SHA 해시를 획득하려면:

  • 정책 적용 섹션에 나와 있는 CSP를 적용합니다.
  • 앱을 로컬로 실행하는 상태에서 브라우저의 개발자 도구 콘솔에 액세스합니다. CSP 헤더 또는 meta 태그가 있는 경우 브라우저가 차단된 스크립트에 대해 해시를 계산하고 표시합니다.
  • 브라우저에 표시된 해시를 script-src 소스로 복사합니다. 해시를 작은따옴표로 묶습니다.

콘텐츠 보안 정책 수준 2 브라우저 지원 매트릭스는 다음을 사용할 수 있습니다. 콘텐츠 보안 정책 수준 2를 참조하세요.

정책 적용

<meta> 태그를 사용하여 정책을 적용합니다.

  • http-equiv 특성의 값을 Content-Security-Policy로 설정합니다.
  • content 특성 값에 지시문을 배치합니다. 지시문을 세미콜론(;)으로 구분합니다.
  • 항상 콘텐츠에 meta 태그를 배치합니다<head>.

다음 섹션에서는 예제 정책을 보여줍니다. 이 문서에서 예제는 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';
               style-src 'self';
               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 https://stackpath.bootstrapcdn.com/ 
                          'self';
               style-src https://stackpath.bootstrapcdn.com/
                         'self' 
                         'unsafe-inline';
               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 https://stackpath.bootstrapcdn.com/ 
                          'self' 
                          'sha256-34WLX60Tw3aG6hylk0plKbZZFXCuepeQ6Hu7OqRf8PI=';
               style-src https://stackpath.bootstrapcdn.com/
                         'self' 
                         'unsafe-inline';
               upgrade-insecure-requests;">

앱에 필요한 더 많은 script-srcstyle-src 해시를 추가합니다. 개발하는 동안 온라인 도구나 브라우저 개발자 도구를 사용하여 해시를 계산합니다. 예를 들어 다음 브라우저 도구 콘솔 오류는 정책에서 다루지 않는 필수 스크립트의 해시를 보고합니다.

다음 콘텐츠 보안 정책 지시문을 위반하기 때문에 인라인 스크립트 실행이 거부되었습니다. “ ... ”. 인라인 실행을 사용하려면 ‘unsafe-inline’ 키워드, 해시(‘sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=’) 또는 nonce(‘nonce-...’) 중 하나가 필요합니다.

오류와 관련된 특정 스크립트가 콘솔에서 오류 옆에 표시됩니다.

클라이언트 쪽 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';
               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';
               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' 
                          'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=' 
                          'unsafe-eval';
               style-src 'self';
               upgrade-insecure-requests;">

참고 항목

해시는 sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA= 클라이언트 쪽 Blazor 앱에 사용되는 인라인 스크립트를 나타냅니다. 이 문제는 나중에 제거될 수 있습니다.

<meta http-equiv="Content-Security-Policy" 
      content="base-uri 'self';
               default-src 'self';
               img-src data: https:;
               object-src 'none';
               script-src https://stackpath.bootstrapcdn.com/ 
                          'self' 
                          'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=' 
                          'unsafe-eval';
               style-src https://stackpath.bootstrapcdn.com/
                         'self'
                         'unsafe-inline';
               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 https://stackpath.bootstrapcdn.com/ 
                          'self' 
                          'sha256-v8ZC9OgMhcnEQ/Me77/R9TlJfzOBqrMTW8e1KuqLaqc=' 
                          'sha256-If//FtbPc03afjLezvWHnC3Nbu4fDM04IIzkPaf3pH0=' 
                          'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=' 
                          'unsafe-eval';
               style-src https://stackpath.bootstrapcdn.com/
                         'self'
                         'unsafe-inline';
               upgrade-insecure-requests;">

앱에 필요한 더 많은 script-srcstyle-src 해시를 추가합니다. 개발하는 동안 온라인 도구나 브라우저 개발자 도구를 사용하여 해시를 계산합니다. 예를 들어 다음 브라우저 도구 콘솔 오류는 정책에서 다루지 않는 필수 스크립트의 해시를 보고합니다.

다음 콘텐츠 보안 정책 지시문을 위반하기 때문에 인라인 스크립트 실행이 거부되었습니다. “ ... ”. 인라인 실행을 사용하려면 ‘unsafe-inline’ 키워드, 해시(‘sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=’) 또는 nonce(‘nonce-...’) 중 하나가 필요합니다.

오류와 관련된 특정 스크립트가 콘솔에서 오류 옆에 표시됩니다.

Development 환경에서 CSP 적용

CSP가 앱의 <head> 콘텐츠에 Blazor 적용되면 환경에서 로컬 테스트를 Development 방해합니다. 예를 들어 브라우저 링크 및 브라우저 새로 고침 스크립트가 로드되지 않습니다. 다음 예제에서는 비Development 환경에서 CSP의 <meta> 태그를 적용하는 방법을 보여 줍니다.

참고 항목

이 섹션의 예제에서는 CSP에 대한 전체 <meta> 태그를 표시하지 않습니다. 전체 <meta> 태그는 이 문서의 앞부분에 있는 정책 적용 섹션의 하위 섹션에서 찾을 수 있습니다.

세 가지 일반적인 방법을 사용할 수 있습니다.

  • 구성 요소를 통해 CSP를 App 적용합니다. 이 구성 요소는 앱의 모든 레이아웃에 CSP를 적용합니다.
  • 앱의 여러 영역에 CSP를 적용해야 하는 경우(예: 관리자 페이지에 대해서만 사용자 지정 CSP) 태그를 사용하여 레이아웃별로 CSP를 <HeadContent> 적용합니다. 완전한 효율성을 위해 모든 앱 레이아웃 파일은 접근 방식을 채택해야 합니다.
  • 호스팅 서비스 또는 서버는 앱의 나가는 응답을 추가한 헤더Content-Security-Policy 통해 CSP를 제공할 수 있습니다. 이 방법은 서비스 또는 서버를 호스팅하는 방법에 따라 다르므로 다음 예제에서는 다루지 않습니다. 이 방법을 채택하려면 호스팅 서비스 공급자 또는 서버에 대한 설명서를 참조하세요.

Blazor 웹앱 접근 방식

구성 요소(Components/App.razor)에서 다음을 App 삽입IHostEnvironment합니다.

@inject IHostEnvironment Env

App 구성 요소의 <head> 콘텐츠에서 환경에 없는 경우 CSP를 Development 적용합니다.

@if (!Env.IsDevelopment())
{
    <meta ...>
}

또는 다음 예제와 같이 폴더의 Components/Layout 레이아웃별로 CSP를 적용합니다. 모든 레이아웃이 CSP를 지정하는지 확인합니다.

@inject IHostEnvironment Env

@if (!Env.IsDevelopment())
{
    <HeadContent>
        <meta ...>
    </HeadContent>
}

Blazor WebAssembly 앱 접근 방식

구성 요소(App.razor)에서 다음을 App 삽입IWebAssemblyHostEnvironment합니다.

@using Microsoft.AspNetCore.Components.WebAssembly.Hosting
@inject IWebAssemblyHostEnvironment Env

App 구성 요소의 <head> 콘텐츠에서 환경에 없는 경우 CSP를 Development 적용합니다.

@if (!Env.IsDevelopment())
{
    <HeadContent>
        <meta ...>
    </HeadContent>
}

또는 이전 코드를 사용하지만 폴더의 레이아웃별로 CSP를 Layout 적용합니다. 모든 레이아웃이 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-to가 완전히 지원되는 시점에 정책에서 report-uri에 대한 지원을 제거하세요. report-to의 채택 여부를 추적하려면 Can I use: report-to(report-to를 사용해도 될까요?)를 참조하세요.

릴리스마다 앱의 정책을 테스트하고 업데이트하시기 바랍니다.

문제 해결

  • 오류는 브라우저의 개발자 도구 콘솔에 표시됩니다. 브라우저는 다음 사항에 대한 정보를 제공합니다.
    • 정책을 준수하지 않는 요소.
    • 차단된 항목을 허용하도록 정책을 수정하는 방법.
  • 정책은 클라이언트의 브라우저에서 포함된 모든 지시문을 지원하는 경우에만 완전히 유효합니다. 현재 브라우저 지원 매트릭스는 다음을 사용할 수 있습니다. Content-Security-Policy를 참조하세요.

추가 리소스