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

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

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

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

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

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

특히 새로운 CSP는 웹사이트에서 대규모 인젝션 공격을 체계적으로 방지할 수 있는 동적 분석을 가능하게 하는 신뢰할 수 있는 유형(TT) 정책입니다. 이를 위해 TT는 특정 유형의 항목만 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가 열리면 이를 사용할 수 있도록 합니다.
  5. 문제 텍스트 디자인. 웹 개발자가 문제를 이해하고 더 중요하게 해결하는 데 도움이 되는 설명 텍스트를 작성합니다.

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

구현 작업을 시작하기 전에 필요한 작업을 더 잘 이해하기 위해 사용자 스토리가 포함된 디자인 문서를 만들었습니다. 예를 들어 다음과 같은 사용자 스토리를 작성했습니다.


웹사이트 일부가 차단된 것을 방금 알게 된 개발자로서 다음과 같은 작업을 하고 싶습니다. - ...CSP가 웹사이트에서 iframe / 이미지를 차단한 이유인지 확인 - 특정 리소스를 차단하는 CSP 지시어 알아보기 - 현재 차단된 리소스의 표시 / 현재 차단된 js의 실행을 허용하도록 웹사이트의 CSP를 변경하는 방법 알아보기


이 사용자 스토리를 살펴보기 위해 관심 있는 CSP 위반을 보여주는 간단한 예시 웹페이지를 만들고 예시 페이지를 탐색하여 프로세스에 익숙해지도록 했습니다. 다음은 웹페이지의 일부 예입니다 (문제 탭을 연 상태에서 데모 열기).

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

2단계: 프런트엔드 구현

Google은 이 유용한 정보를 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는 이 위반으로 인해 중단점이 트리거되어야 하는지 확인하고, 이 경우 프런트엔드에 메시지를 보내 실행을 일시중지합니다.

지금까지 수행한 작업 및 다음 단계는 무엇인가요?

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

앞으로는 Issues 탭을 사용하여 더 많은 문제를 표시할 계획입니다. 그러면 장기적으로 읽을 수 없는 오류 메시지 흐름의 Console을 언로드할 수 있게 됩니다.

미리보기 채널 다운로드

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

Chrome DevTools 팀에 문의하기

다음 옵션을 사용하여 게시물의 새로운 기능과 변경 사항 또는 DevTools와 관련된 다른 사항에 대해 논의하세요.

  • crbug.com을 통해 제안이나 의견을 보내주세요.
  • 옵션 더보기   더보기 >를 사용하여 DevTools 문제 신고 도움말 > DevTools에서 DevTools 문제를 신고합니다.
  • @ChromeDevTools에서 트윗하세요.
  • DevTools의 새로운 기능 YouTube 동영상 또는 DevTools 도움말 YouTube 동영상에 의견을 남겨주세요.