Triển khai quy trình gỡ lỗi CSP và loại đáng tin cậy trong Công cụ của Chrome cho nhà phát triển

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

Bài đăng trên blog này nói về việc triển khai tính năng hỗ trợ Công cụ cho nhà phát triển để gỡ lỗi các vấn đề về Chính sách bảo mật nội dung (CSP) với sự trợ giúp của thẻ Vấn đề được giới thiệu gần đây.

Công việc triển khai được thực hiện trong 2 đợt thực tập: 1. Trong giai đoạn đầu tiên, chúng tôi đã xây dựng khung báo cáo chung và thiết kế thông báo vấn đề cho 3 vấn đề về lỗi vi phạm CSP. 2. Trong phần thứ hai, chúng tôi bổ sung vấn đề về Loại đáng tin cậy cùng với một số tính năng Công cụ cho nhà phát triển chuyên biệt để gỡ lỗi Loại đáng tin cậy.

Chính sách bảo mật nội dung là gì?

Chính sách bảo mật nội dung (CSP) cho phép hạn chế một số hành vi nhất định trên trang web để tăng tính bảo mật. Ví dụ: bạn có thể dùng CSP để không cho phép các tập lệnh cùng dòng hoặc không cho phép eval, cả hai đều làm giảm khu vực tấn công đối với các cuộc tấn công Tập lệnh trên nhiều trang web (XSS). Để xem hướng dẫn chi tiết về CSP, hãy đọc tại đây.

Một CSP đặc biệt mới là chính sách Loại đáng tin cậy(TT), cho phép phân tích động có thể ngăn chặn một loạt các cuộc tấn công chèn quảng cáo trên các trang web một cách có hệ thống. Để đạt được điều này, TT hỗ trợ một trang web kiểm soát mã JavaScript của trang web để chỉ cho phép một số loại nội dung nhất định được chỉ định cho các bồn lưu trữ DOM, chẳng hạn như innerHTML.

Một trang web có thể kích hoạt chính sách bảo mật nội dung bằng cách thêm một tiêu đề HTTP cụ thể. Ví dụ: tiêu đề content-security-policy: require-trusted-types-for 'script'; trusted-types default sẽ kích hoạt chính sách TT cho một trang.

Mỗi chính sách có thể hoạt động ở một trong các chế độ sau:

  • chế độ thực thi – trong đó mỗi lỗi vi phạm chính sách đều là một lỗi,
  • chế độ chỉ báo cáo – chế độ này báo cáo thông báo lỗi dưới dạng cảnh báo nhưng không gây ra lỗi trong trang web.

Triển khai vấn đề về chính sách bảo mật nội dung trong thẻ Vấn đề

Mục tiêu của việc này là cải thiện quy trình gỡ lỗi cho các vấn đề về CSP. Khi xem xét các vấn đề mới, nhóm phụ trách Công cụ cho nhà phát triển tuân theo quy trình sau đây:

  1. Xác định câu chuyện của người dùng. Xác định tập hợp câu chuyện của người dùng trong giao diện người dùng của Công cụ cho nhà phát triển trình bày cách nhà phát triển web cần tìm hiểu sự cố.
  2. Triển khai giao diện người dùng. Dựa vào câu chuyện của người dùng, hãy xác định thông tin nào cần thiết cho việc điều tra sự cố ở giao diện người dùng (ví dụ: yêu cầu có liên quan, tên của cookie, dòng trong tập lệnh hoặc tệp html, v.v.).
  3. Phát hiện vấn đề. Xác định những vị trí trong trình duyệt nơi có thể phát hiện vấn đề trong Chrome và đo lường nơi báo cáo vấn đề, bao gồm cả thông tin liên quan trong bước (2).
  4. Lưu và hiển thị vấn đề. Lưu trữ các vấn đề vào một nơi thích hợp và cung cấp chúng cho Công cụ cho nhà phát triển sau khi mở
  5. Thiết kế văn bản cho vấn đề. Hãy đưa ra văn bản giải thích giúp nhà phát triển web hiểu được và quan trọng hơn là khắc phục được vấn đề

Bước 1: xác định câu chuyện của người dùng liên quan đến các vấn đề về CSP

Trước khi bắt đầu công việc triển khai, chúng tôi đã tạo một tài liệu thiết kế chứa câu chuyện của người dùng để hiểu rõ hơn về những việc chúng tôi cần làm. Ví dụ: chúng tôi đã viết ra câu chuyện sau đây của người dùng:


Là một nhà phát triển, vừa nhận ra một số phần trên trang web của mình bị chặn, tôi muốn:- - ...tìm hiểu xem CSP có phải là lý do khiến iframe / hình ảnh trên trang web của tôi bị chặn hay không - ...tìm hiểu xem lệnh CSP nào gây ra tình trạng chặn một tài nguyên cụ thể nào đó hay không - ...biết cách thay đổi CSP của trang web để cho phép hiển thị các tài nguyên hiện bị chặn / thực thi các js hiện bị chặn.


Để tìm hiểu câu chuyện của người dùng này, chúng tôi đã tạo một số trang web mẫu đơn giản cho thấy các lỗi vi phạm CSP mà chúng tôi quan tâm, đồng thời khám phá các trang ví dụ đó để tự làm quen với quy trình. Sau đây là một số trang web ví dụ (hãy mở bản minh hoạ khi thẻ Vấn đề đang mở):

Qua quy trình này, chúng tôi biết được rằng vị trí nguồn là thông tin quan trọng nhất để gỡ lỗi các vấn đề về CSP. Chúng tôi cũng thấy hữu ích khi nhanh chóng tìm thấy iframe được liên kết và yêu cầu trong trường hợp tài nguyên bị chặn và đường liên kết trực tiếp đến phần tử HTML trong bảng Phần tử của Công cụ cho nhà phát triển cũng có thể hữu ích.

Bước 2: triển khai giao diện người dùng

Chúng tôi đã biến thông tin chi tiết này thành bản nháp đầu tiên về thông tin mà chúng tôi muốn cung cấp cho Công cụ cho nhà phát triển thông qua Giao thức Công cụ của Chrome cho nhà phát triển (CDP):

Dưới đây là phần trích dẫn từ 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

Định nghĩa ở trên về cơ bản mã hoá cấu trúc dữ liệu JSON. Ngôn ngữ này được viết bằng một ngôn ngữ đơn giản gọi là PDL (ngôn ngữ dữ liệu giao thức). PDL được sử dụng cho hai mục đích. Trước tiên, chúng tôi sử dụng PDL để tạo các định nghĩa TypeScript mà giao diện người dùng của Công cụ cho nhà phát triển dựa vào. Ví dụ: định nghĩa PDL ở trên tạo ra giao diện TypeScript sau:

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;
}

Thứ hai và có lẽ quan trọng hơn, chúng tôi tạo thư viện C++ từ định nghĩa giúp xử lý việc tạo và gửi các cấu trúc dữ liệu này từ phần phụ trợ Chromium C++ đến giao diện người dùng của Công cụ cho nhà phát triển. Khi sử dụng thư viện đó, bạn có thể tạo đối tượng ContentSecurityPolicyIssueDetails bằng đoạn mã C++ sau:

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

Sau khi đã xác định được thông tin mình muốn cung cấp, chúng tôi cần tìm hiểu nơi lấy thông tin này từ Chromium.

Bước 3: phát hiện vấn đề

Để cung cấp thông tin cho Giao thức Công cụ của Chrome cho nhà phát triển (CDP) theo định dạng được mô tả trong phần cuối, chúng tôi cần tìm vị trí nơi thông tin thực sự có sẵn trong phần phụ trợ. Rất may là mã CSP đã có một nút thắt cổ chai được dùng cho chế độ chỉ báo cáo, nơi chúng tôi có thể kết nối: ContentSecurityPolicy::ReportViolation báo cáo sự cố đến điểm cuối báo cáo (không bắt buộc) có thể được định cấu hình trong tiêu đề HTTP CSP. Hầu hết thông tin chúng tôi muốn báo cáo đều đã có sẵn, do đó, khả năng đo lường của chúng tôi không cần thực hiện thay đổi lớn nào trong chương trình phụ trợ.

Bước 4: lưu và hiển thị vấn đề

Một phức tạp nhỏ là chúng tôi cũng muốn báo cáo các vấn đề xảy ra trước khi Công cụ cho nhà phát triển được mở, tương tự như cách xử lý các thông báo trên bảng điều khiển. Điều này có nghĩa là chúng tôi không báo cáo vấn đề ngay lập tức cho giao diện người dùng mà sử dụng bộ nhớ chứa các vấn đề một cách độc lập bất kể Công cụ cho nhà phát triển có đang mở hay không. Sau khi Công cụ cho nhà phát triển được mở (hoặc nếu có ứng dụng CDP khác được đính kèm), bạn có thể phát lại tất cả vấn đề đã ghi lại trước đó từ bộ nhớ.

Việc này đã kết thúc công việc ở phần phụ trợ và giờ đây chúng tôi cần tập trung vào cách giải quyết vấn đề ở giao diện người dùng.

Bước 5: thiết kế nội dung vấn đề

Việc thiết kế văn bản về vấn đề là quá trình có sự tham gia của nhiều nhóm khác ngoài đội ngũ của chúng tôi. Ví dụ: chúng tôi thường dựa vào thông tin chi tiết từ nhóm triển khai một tính năng (trong trường hợp này là nhóm CSP) và tất nhiên là nhóm DevRel. Nhóm này sẽ thiết kế cách xử lý của các nhà phát triển web khi xử lý một loại vấn đề nào đó. Văn bản vấn đề thường trải qua một số bước tinh chỉnh cho đến khi hoàn tất.

Thông thường, nhóm Công cụ cho nhà phát triển sẽ bắt đầu với bản nháp sơ bộ về những gì họ tưởng tượng:


## 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/

Sau khi lặp lại, chúng tôi đã đi đến:

ALT_TEXT_HERE

Như bạn có thể thấy, việc liên quan đến nhóm phụ trách tính năng và DevRel giúp nội dung mô tả trở nên rõ ràng và chính xác hơn rất nhiều!

Bạn cũng có thể tìm thấy vấn đề về CSP trên trang của mình trong thẻ dành riêng cho các lỗi vi phạm về CSP.

Gỡ lỗi các loại đáng tin cậy

Việc hợp tác với TT ở quy mô lớn có thể khó khăn nếu không có các công cụ phù hợp cho nhà phát triển.

Cải thiện tính năng in trên bảng điều khiển

Khi làm việc với Đối tượng đáng tin cậy, chúng ta muốn hiển thị ít nhất một lượng thông tin bằng với đối tượng không đáng tin cậy. Rất tiếc, hiện tại khi hiển thị Đối tượng đáng tin cậy thì không có thông tin nào về đối tượng được bao bọc được hiển thị.

Đó là vì giá trị hiển thị trong bảng điều khiển được lấy từ việc gọi .valueOf() trên đối tượng theo mặc định. Tuy nhiên, trong trường hợp Loại đáng tin cậy, giá trị trả về không hữu ích lắm. Thay vào đó, chúng tôi muốn có một nội dung tương tự như nội dung bạn nhận được khi gọi .toString(). Để đạt được điều này, chúng ta cần sửa đổi V8 và Blink để áp dụng cách xử lý đặc biệt cho các đối tượng thuộc loại đáng tin cậy.

Vì những lý do trước đây nên việc xử lý tuỳ chỉnh này được thực hiện trong phiên bản 8, nhưng phương pháp này có những nhược điểm quan trọng. Có nhiều đối tượng yêu cầu hiển thị tuỳ chỉnh nhưng có cùng loại đối tượng ở cấp JS. Vì V8 là JS thuần tuý, nên V8 không thể phân biệt các khái niệm tương ứng với một API Web, chẳng hạn như Loại đáng tin cậy. Do đó, V8 phải yêu cầu trình nhúng (Blink) giúp phân biệt chúng.

Do đó, việc di chuyển phần mã đó sang Blink hoặc bất kỳ trình nhúng nào có vẻ là một lựa chọn hợp lý. Ngoài vấn đề bị lộ, bạn còn được hưởng nhiều lợi ích khác:

  • Mỗi trình nhúng có thể tạo nội dung mô tả riêng
  • Dễ dàng tạo nội dung mô tả hơn thông qua Blink API
  • Blink có quyền truy cập vào định nghĩa ban đầu của đối tượng. Do đó, nếu chúng ta sử dụng .toString() để tạo nội dung mô tả, thì không có nguy cơ rằng .toString() có thể được định nghĩa lại.

Ngắt khi vi phạm (ở chế độ chỉ báo cáo)

Hiện tại, cách duy nhất để gỡ lỗi vi phạm TT là đặt điểm ngắt cho ngoại lệ JS. Vì vi phạm TT bắt buộc sẽ kích hoạt một ngoại lệ, tính năng này có thể hữu ích theo cách nào đó. Tuy nhiên, trong các tình huống thực tế, bạn cần kiểm soát chi tiết hơn các trường hợp vi phạm TT. Cụ thể, chúng tôi chỉ muốn ngắt quảng cáo trên các vi phạm về TT (không phải trường hợp ngoại lệ khác), ngắt cũng ở chế độ chỉ báo cáo và phân biệt giữa các loại vi phạm khác nhau về TT.

Công cụ cho nhà phát triển đã hỗ trợ nhiều điểm ngắt, vì vậy, cấu trúc khá có thể mở rộng. Để thêm loại điểm ngắt mới, bạn phải thực hiện các thay đổi trong phần phụ trợ (Blink), CDP và giao diện người dùng. Chúng ta sẽ ra mắt một lệnh CDP mới, hãy đặt tên là setBreakOnTTViolation. Lệnh này sẽ được giao diện người dùng sử dụng để cho phần phụ trợ biết về loại vi phạm TT nào mà nó nên phá vỡ. Cụ thể là InspectorDOMDebuggerAgent, phần phụ trợ sẽ cung cấp một "đầu dò", onTTViolation() sẽ được gọi mỗi khi xảy ra lỗi vi phạm TT. Sau đó, InspectorDOMDebuggerAgent sẽ kiểm tra xem lỗi vi phạm đó có kích hoạt điểm ngắt hay không. Nếu đúng như vậy, hệ thống sẽ gửi thông báo đến giao diện người dùng để tạm dừng việc thực thi.

Việc cần làm và việc cần làm tiếp theo

Kể từ khi các vấn đề được mô tả ở đây, thẻ Vấn đề đã có một số thay đổi:

Từ giờ trở đi, chúng tôi dự định sẽ sử dụng thẻ Vấn đề để phát hiện thêm nhiều vấn đề. Nhờ đó về lâu dài, bạn có thể huỷ tải quy trình thông báo lỗi không đọc được trên Console.

Tải kênh xem trước xuống

Hãy cân nhắc sử dụng Chrome Canary, Dev hoặc Beta làm trình duyệt phát triển mặc định. Các kênh xem trước này cung cấp cho bạn quyền truy cập vào các tính năng mới nhất của Công cụ cho nhà phát triển, thử nghiệm API nền tảng web tiên tiến và tìm ra sự cố trên trang web của bạn trước khi người dùng của bạn làm điều đó!

Liên hệ với nhóm Công cụ của Chrome cho nhà phát triển

Sử dụng các lựa chọn sau đây để thảo luận về các tính năng mới và thay đổi trong bài đăng hoặc bất cứ vấn đề nào khác liên quan đến Công cụ cho nhà phát triển.

  • Hãy gửi đề xuất hoặc phản hồi cho chúng tôi qua crbug.com.
  • Báo cáo sự cố của Công cụ cho nhà phát triển bằng cách sử dụng phần Tuỳ chọn khác   Thêm   > Trợ giúp > Báo cáo sự cố về Công cụ cho nhà phát triển trong Công cụ cho nhà phát triển.
  • Tweet tại @ChromeDevTools.
  • Hãy để lại bình luận về tính năng mới trong video trên YouTube của Công cụ cho nhà phát triển hoặc video trên YouTube.