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

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

이 블로그 게시물에서는 CSP (Content Security Policy) 문제 디버깅을 위한 DevTools 지원 기능을 구현하고 최근 도입된 문제에 관한 내용을 다룹니다.

구현 작업은 다음과 같은 두 번의 인턴십 과정에서 이루어졌습니다. 1. 첫 번째 단계에서는 일반 보고 프레임워크를 구축하고 3개의 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. 문제 감지. 브라우저에서 문제를 감지할 수 있는 위치를 파악하고 위치를 계측하여 (2)단계의 관련 정보를 포함하여 문제를 신고합니다.
  4. 문제 저장 및 표시 문제를 적절한 위치에 저장하고, 파일이 열렸을 때 DevTools에서 사용할 수 있도록 합니다.
  5. 문제 텍스트 설계. 웹 개발자가 문제를 이해하고 더 중요한 것은 문제를 해결하는 데 도움이 되는 설명 텍스트를 작성합니다.

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

Google은 구현 작업을 시작하기 전에 필요한 사용자 사례를 더 잘 이해하기 위해 사용자 사례를 담은 디자인 문서를 만들었습니다. 예를 들어 다음과 같은 사용자 사례를 정리해 두었습니다.


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


이 사용자 스토리를 살펴보기 위해 관심이 가는 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단계: 문제 텍스트 설계

문제 텍스트 설계는 자체 팀 외에도 여러 팀이 참여하는 프로세스입니다. 예를 들어 기능을 구현하는 팀 (이 경우에는 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 API를 통해 설명을 생성하는 것이 훨씬 쉽습니다.
  • Blink는 객체의 원래 정의에 액세스할 수 있습니다. 따라서 .toString()를 사용하여 설명을 생성하면 .toString()가 재정의될 위험이 없습니다.

위반 차단 (보고서 전용 모드)

현재 TT 위반을 디버깅하는 유일한 방법은 JS 예외에 중단점을 설정하는 것입니다. 시행된 TT 규정 위반은 예외를 트리거하므로 이 기능이 도움이 될 수 있습니다. 하지만 실제 상황에서는 TT 위반을 보다 세밀하게 제어해야 합니다. 특히 다른 예외가 아닌 TT 위반 시에만 중단하고, 보고서 전용 모드에서도 중단하며, 다양한 TT 위반 유형을 구분하려고 합니다.

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

무엇을 해야 하고 다음 단계는 무엇일까요?

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

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

미리보기 채널 다운로드

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

Chrome DevTools팀에 문의하기

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

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