Chrome DevTools에서 CSP 및 신뢰할 수 있는 유형 디버깅 구현

Kateryna Prokopenko
Kateryna Prokopenko
Alfonso Castaño
Alfonso Castaño

이 블로그 게시물에서는 최근에 도입된 문제을 사용하여 콘텐츠 보안 정책 (CSP) 문제를 디버그하기 위한 DevTools 지원 구현에 대해 설명합니다.

구현 작업은 두 번의 인턴십 과정에서 이루어졌습니다. 1. 첫 번째 단계에서는 일반적인 보고 프레임워크를 빌드하고 CSP 위반 문제 3가지에 대한 문제 메시지를 설계했습니다. 2. 두 번째 과정에서는 신뢰할 수 있는 유형 디버깅을 위한 몇 가지 특수한 DevTools 기능과 함께 신뢰할 수 있는 유형 문제를 추가했습니다.

콘텐츠 보안 정책이란 무엇인가요?

콘텐츠 보안 정책 (CSP)을 사용하면 웹사이트에서 특정 동작을 제한하여 보안을 강화할 수 있습니다. 예를 들어 CSP를 사용하여 인라인 스크립트를 허용하지 않거나 eval를 허용하지 않을 수 있습니다. 이 두 가지 모두 교차 사이트 스크립팅 (XSS) 공격의 공격 노출 영역을 줄입니다. CSP에 관한 자세한 소개는 여기를 참고하세요.

특히 새로운 CSP는 웹사이트에서 다양한 삽입 공격을 체계적으로 방지할 수 있는 동적 분석을 사용 설정하는 신뢰할 수 있는 유형(TT) 정책입니다. 이를 위해 TT는 웹사이트에서 JavaScript 코드를 검사하여 특정 유형의 항목만 innerHTML과 같은 DOM 싱크에 할당되도록 지원합니다.

웹사이트는 특정 HTTP 헤더를 포함하여 콘텐츠 보안 정책을 활성화할 수 있습니다. 예를 들어 content-security-policy: require-trusted-types-for 'script'; trusted-types default 헤더는 페이지의 TT 정책을 활성화합니다.

각 정책은 다음 모드 중 하나에서 작동할 수 있습니다.

  • 강제 적용 모드 - 모든 정책 위반이 오류가 됩니다.
  • 보고서 전용 모드 - 오류 메시지를 경고로 보고하지만 웹페이지에 오류를 일으키지 않습니다.

문제 탭에서 콘텐츠 보안 정책 문제 구현

이 작업의 목표는 CSP 문제의 디버깅 환경을 개선하는 것이었습니다. DevTools팀은 새로운 문제를 고려할 때 대략 다음과 같은 절차를 따릅니다.

  1. 사용자 스토리 정의 DevTools 프런트엔드에서 웹 개발자가 문제를 조사하는 데 필요한 방법을 다루는 일련의 사용자 스토리를 식별합니다.
  2. 프런트엔드 구현. 사용자 사례를 바탕으로 프런트엔드에서 문제를 조사하는 데 필요한 정보 (예: 관련 요청, 쿠키의 이름, 스크립트 또는 html 파일의 행 등)를 식별합니다.
  3. 문제 감지 Chrome에서 문제를 감지할 수 있는 브라우저 위치를 식별하고 (2)단계의 관련 정보를 포함하여 문제를 신고할 수 있도록 위치를 설정합니다.
  4. 문제를 저장하고 표시합니다. 문제를 적절한 위치에 저장하고 DevTools가 열리면 DevTools에서 사용할 수 있도록 합니다.
  5. 문제 텍스트 설계 웹 개발자가 문제를 이해하고 해결하는 데 도움이 되는 설명 텍스트를 작성합니다.

1단계: CSP 문제의 사용자 스토리 정의

구현 작업을 시작하기 전에 해야 할 일을 더 잘 이해하기 위해 사용자 스토리가 포함된 설계 문서를 작성했습니다. 예를 들어 다음과 같은 사용자 스토리를 작성했습니다.


웹사이트의 일부가 차단되었다는 사실을 방금 알게 된 개발자는 다음을 수행해야 합니다.- - ...CSP가 웹사이트에서 차단된 iframe / 이미지의 원인인지 확인합니다. - ...특정 리소스가 차단되는 원인이 되는 CSP 디렉티브를 알아봅니다. - ...현재 차단된 리소스의 표시 / 현재 차단된 js의 실행을 허용하도록 웹사이트의 CSP를 변경하는 방법을 알아봅니다.


이 사용자 스토리를 살펴보기 위해 관심 있는 CSP 위반을 보여주는 간단한 예시 웹페이지를 만들고 예시 페이지를 살펴보면서 프로세스를 직접 익혔습니다. 다음은 웹페이지의 예입니다 (문제 탭이 열려 있는 상태에서 데모를 엽니다).

이 프로세스를 통해 소스 위치가 CSP 문제를 디버깅하는 데 가장 중요한 정보라는 것을 알게 되었습니다. 또한 리소스가 차단된 경우 관련 iframe과 요청을 빠르게 찾는 것이 유용하며 DevTools의 요소 패널에 있는 HTML 요소로의 직접 링크도 유용할 수 있습니다.

2단계: 프런트엔드 구현

이러한 통계를 바탕으로 Chrome DevTools 프로토콜 (CDP)을 통해 DevTools에 제공하려는 정보의 초안을 작성했습니다.

다음은 third_party/blink/public/devtools_protocol/browser_protocol.pdl에서 발췌한 내용입니다.

 type ContentSecurityPolicyIssueDetails extends object
   properties
     # The url not included in allowed sources.
     optional string blockedURL
     # Specific directive that is violated, causing the CSP issue.
     string violatedDirective
     boolean isReportOnly
     ContentSecurityPolicyViolationType contentSecurityPolicyViolationType
     optional AffectedFrame frameAncestor
     optional SourceCodeLocation sourceCodeLocation
     optional DOM.BackendNodeId violatingNodeId

위의 정의는 기본적으로 JSON 데이터 구조를 인코딩합니다. PDL (프로토콜 데이터 언어)이라는 간단한 언어로 작성됩니다. PDL은 두 가지 목적으로 사용됩니다. 먼저 PDL을 사용하여 DevTools 프런트엔드에서 사용하는 TypeScript 정의를 생성합니다. 예를 들어 위의 PDL 정의는 다음과 같은 TypeScript 인터페이스를 생성합니다.

export interface ContentSecurityPolicyIssueDetails {
  /**
  * The url not included in allowed sources.
  */
  blockedURL?: string;
  /**
  * Specific directive that is violated, causing the CSP issue.
  */
  violatedDirective: string;
  isReportOnly: boolean;
  contentSecurityPolicyViolationType: ContentSecurityPolicyViolationType;
  frameAncestor?: AffectedFrame;
  sourceCodeLocation?: SourceCodeLocation;
  violatingNodeId?: DOM.BackendNodeId;
}

둘째, 그리고 더 중요한 점은 이러한 데이터 구조를 C++ Chromium 백엔드에서 DevTools 프런트엔드로 생성하고 전송하는 작업을 처리하는 정의에서 C++ 라이브러리를 생성한다는 것입니다. 이 라이브러리를 사용하면 다음 C++ 코드를 사용하여 ContentSecurityPolicyIssueDetails 객체를 만들 수 있습니다.

protocol::Audits::ContentSecurityPolicyIssueDetails::create()
  .setViolatedDirective(d->violated_directive)
  .setIsReportOnly(d->is_report_only)
  .setContentSecurityPolicyViolationType(BuildViolationType(
      d->content_security_policy_violation_type)))
  .build();

어떤 정보를 제공하고 싶은지 결정한 후에는 Chromium에서 이 정보를 가져올 위치를 찾아야 했습니다.

3단계: 문제 감지

이전 섹션에서 설명한 형식으로 Chrome DevTools 프로토콜 (CDP)에 정보를 제공하려면 백엔드에서 실제로 정보를 사용할 수 있는 위치를 찾아야 했습니다. 다행히 CSP 코드에는 이미 보고 전용 모드에 사용되는 병목 현상이 있었습니다. 여기서 다음을 연결할 수 있습니다. ContentSecurityPolicy::ReportViolationCSP HTTP 헤더에서 구성할 수 있는 (선택사항) 보고 엔드포인트에 문제를 보고합니다. 보고하려는 정보의 대부분은 이미 제공되고 있었으므로 계측을 사용하기 위해 백엔드를 크게 변경할 필요가 없었습니다.

4단계: 문제를 저장하고 표시

약간의 복잡성은 콘솔 메시지가 처리되는 방식과 마찬가지로 DevTools가 열리기 전에 발생한 문제도 보고하고자 했다는 점입니다. 즉, 문제를 프런트엔드에 바로 보고하지 않고 DevTools가 열려 있는지 여부와 관계없이 문제로 채워진 저장소를 사용합니다. DevTools가 열리거나 다른 CDP 클라이언트가 연결되면 이전에 기록된 모든 문제를 저장소에서 재생할 수 있습니다.

백엔드 작업이 완료되었으므로 이제 프런트엔드에서 문제를 표시하는 방법에 집중해야 했습니다.

5단계: 문제 텍스트 디자인

문제 텍스트를 디자인하는 작업은 Google팀 외에도 여러 팀이 포함된 프로세스입니다. 예를 들어 기능을 구현하는 팀 (이 경우 CSP팀)과 웹 개발자가 특정 유형의 문제를 처리하는 방법을 설계하는 DevRel팀의 인사이트를 활용하는 경우가 많습니다. 일반적으로 문제 텍스트는 완료될 때까지 약간의 조정을 거칩니다.

일반적으로 DevTools팀은 자신이 생각하는 대략적인 초안으로 시작합니다.


## Header
Content Security Policy: include all sources of your resources in content security policy header to improve the functioning of your site

## General information
Even though some sources are included in the content security policy header, some resources accessed by your site like images, stylesheets or scripts originate from sources not included in content security policy directives.

Usage of content from not included sources is restricted to strengthen the security of your entire site.

## Specific information

### VIOLATED DIRECTIVES
`img-src 'self'`

### BLOCKED URLs
https://imgur.com/JuXCo1p.jpg

## Specific information
https://web.dev/strict-csp/

반복 후 다음과 같은 결과가 도출되었습니다.

ALT_TEXT_HERE

보시다시피 기능팀과 DevRel을 참여시키면 설명이 훨씬 더 명확하고 정확해집니다.

페이지의 CSP 문제는 CSP 위반 전용 탭에서도 확인할 수 있습니다.

신뢰할 수 있는 유형 문제 디버깅

적절한 개발자 도구가 없으면 대규모로 TT를 사용하는 것이 어려울 수 있습니다.

콘솔 인쇄 개선

신뢰할 수 있는 객체를 사용할 때는 신뢰할 수 없는 객체에 대해 최소한 동일한 양의 정보를 표시하려고 합니다. 안타깝게도 현재 신뢰할 수 있는 객체를 표시할 때 래핑된 객체에 대한 정보는 표시되지 않습니다.

콘솔에 표시되는 값은 기본적으로 객체에서 .valueOf()를 호출할 때 가져옵니다. 그러나 신뢰할 수 있는 유형의 경우 반환된 값은 그다지 유용하지 않습니다. 대신 .toString()를 호출할 때 얻는 것과 유사한 내용을 만들고자 합니다. 이를 위해 V8 및 Blink를 수정하여 신뢰할 수 있는 유형 객체에 대한 특수 처리를 도입해야 합니다.

이전에는 역사적인 이유로 이 맞춤 처리가 V8에서 이루어졌지만 이러한 접근 방식에는 중요한 단점이 있습니다. 맞춤 표시가 필요하지만 JS 수준에서 유형이 동일한 객체가 많이 있습니다. V8은 순수 JS이므로 신뢰할 수 있는 유형과 같이 웹 API에 해당하는 개념을 구분할 수 없습니다. 따라서 V8은 이를 구분하기 위해 삽입자 (Blink)에게 도움을 요청해야 합니다.

따라서 코드의 해당 부분을 Blink 또는 임베더로 이동하는 것이 논리적인 선택으로 보입니다. 노출된 문제 외에도 다음과 같은 여러 이점이 있습니다.

  • 삽입한 각 사용자에게 자체 설명 생성이 있을 수 있음
  • Blink API를 통해 설명을 생성하는 것이 훨씬 쉽습니다.
  • Blink는 객체의 원래 정의에 액세스할 수 있습니다. 따라서 .toString()를 사용하여 설명을 생성하면 .toString()가 재정의될 위험이 없습니다.

위반 시 중단 (보고 전용 모드)

현재 TT 위반을 디버그하는 유일한 방법은 JS 예외에 브레이크포인트를 설정하는 것입니다. 적용된 TT 위반은 예외를 트리거하므로 이 기능이 유용할 수 있습니다. 그러나 실제 시나리오에서는 TT 위반을 더 세부적으로 제어해야 합니다. 특히 다른 예외가 아닌 TT 위반에 대해서만 분류하고, 보고서 전용 모드에서도 분류하고, 서로 다른 유형의 TT 위반을 구분하려고 합니다.

DevTools에는 이미 매우 다양한 중단점이 지원되므로 아키텍처가 상당히 확장 가능합니다. 새 브레이크포인트 유형을 추가하려면 백엔드 (Blink), CDP, 프런트엔드를 변경해야 합니다. 새 CDP 명령어를 도입해야 하며 setBreakOnTTViolation이라고 하겠습니다. 이 명령어는 프런트엔드에서 백엔드에 어떤 종류의 TT 위반을 중단해야 하는지 알려주는 데 사용됩니다. 백엔드, 특히 InspectorDOMDebuggerAgent는 TT 위반이 발생할 때마다 호출되는 '프로브' onTTViolation()를 제공합니다. 그런 다음 InspectorDOMDebuggerAgent는 이 위반으로 인해 중단점이 트리거되어야 하는지 확인하고, 중단점이 트리거되어야 하는 경우 실행을 일시중지하도록 프런트엔드에 메시지를 전송합니다.

현재 단계와 다음 단계는 무엇인가요?

여기에 설명된 문제가 도입된 이후 문제 탭이 상당히 변경되었습니다.

앞으로는 문제 탭을 사용하여 더 많은 문제를 표시할 계획입니다. 이를 통해 장기적으로는 읽을 수 없는 오류 메시지 흐름을 콘솔에서 로드 해제할 수 있습니다.

미리보기 채널 다운로드

Chrome Canary, Dev 또는 베타를 기본 개발 브라우저로 사용하는 것이 좋습니다. 이러한 미리보기 채널을 통해 최신 DevTools 기능에 액세스할 수 있고, 최첨단 웹 플랫폼 API를 테스트할 수 있으며, 사용자보다 먼저 사이트에서 문제를 발견할 수 있습니다.

Chrome DevTools팀에 문의하기

다음 옵션을 사용하여 DevTools와 관련된 새로운 기능, 업데이트 또는 기타 사항을 논의하세요.