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 trình bày cách 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 đề mới ra mắt.

Công việc triển khai được thực hiện trong 2 đợt thực tập: 1. Trong chương trình đầ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 riêng cho 3 vấn đề về lỗi vi phạm Chính sách bảo mật nội dung (CSP). 2. Trong lần thứ hai, chúng tôi đã thêm các vấn đề về Loại đáng tin cậy cùng với một số tính năng chuyên biệt trong Công cụ cho nhà phát triển để gỡ lỗi về 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 một trang web để tăng tính bảo mật. Ví dụ: bạn có thể dùng CSP để chặn các tập lệnh cùng dòng hoặc không cho phép eval. Cả hai cách này đều làm giảm bề mặt tấn công cho các cuộc tấn công bằng cách tấn công Cross-Site Scripting (XSS). Để tìm hiểu thông tin giới thiệu chi tiết về CSP, hãy đọc tại đây.

Một CSP đặc biệt mới là chính sách Các loại đáng tin cậy(TT), cho phép phân tích động một cách có hệ thống để ngăn chặn một cách có hệ thống một loạt các cuộc tấn công chèn mã độc trên các trang web. Để đạt được điều này, TT hỗ trợ trang web kiểm soát mã JavaScript để chỉ cho phép gán một số loại nội dung nhất định cho 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 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 trên trang web.

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

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

  1. Xác định câu chuyện của người dùng. Xác định một 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, trong đó trình bày cách thức mà một nhà phát triển web cần để điều tra vấn đề.
  2. Triển khai giao diện người dùng. Dựa trên câu chuyện của người dùng, xác định những thông tin nào cần thiết để điều tra vấn đề trong 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 các vị trí trong trình duyệt có thể phát hiện thấy vấn đề trong Chrome và thiết lập nơi báo cáo vấn đề, bao gồm cả thông tin liên quan ở bước (2).
  4. Lưu và hiển thị vấn đề. Lưu trữ các vấn đề vào nơi thích hợp và đưa chúng vào Công cụ cho nhà phát triển khi ứng dụng được mở
  5. Thiết kế văn bản báo cáo vấn đề. Hãy nghĩ ra nội dung giải thích giúp nhà phát triển web hiểu và quan trọng hơn là có thể khắc phục vấn đề

Bước 1: Xác định câu chuyện của người dùng cho 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ế có 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 người dùng như sau:


Là một nhà phát triển, khi vừa nhận ra rằng 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à nguyên nhân khiến iframe / hình ảnh bị chặn trên trang web của tôi không – ...tìm hiểu lệnh CSP nào gây ra tình trạng chặn một tài nguyên nhất định - ...biết cách thay đổi CSP của trang web để cho phép hiển thị tài nguyên bị chặn / thực thi js hiện bị chặn.


Để khám phá 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. Dưới đây là một số trang web ví dụ (mở bản minh hoạ và mở thẻ Vấn đề):

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 rằng bạn nên 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. Ngoài ra, một đường liên kết trực tiếp đến phần tử HTML trong bảng điều khiển Elements 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 đã chuyển thông tin chi tiết này thành bản nháp thông tin đầu tiên 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 là mã hoá cấu trúc dữ liệu JSON. Mã này được viết bằng một ngôn ngữ đơn giản có tên 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ô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ó thể là quan trọng hơn, chúng ta sẽ tạo một thư viện C++ từ phần định nghĩa có khả năng 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 quyết định xem thông tin nào chúng tôi muốn cung cấp, chúng tôi cần khám phá nơi có thể 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) ở định dạng được mô tả trong phần trước, chúng ta cần tìm vị trí thực sự có sẵn thông tin trong phần phụ trợ. May mắn là mã CSP đã gây ra nút thắt cổ chai dùng cho chế độ chỉ báo cáo, ở đó chúng ta có thể kết nối vào: ContentSecurityPolicy::ReportViolation báo cáo vấn đề tới một đ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 đã có sẵn, vì vậy, các chức 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 phần phụ trợ.

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

Một điều phức tạp nhỏ là việc chúng ta 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ý 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 ngay vấn đề cho giao diện người dùng, mà sử dụng một bộ nhớ có vấn đề không phụ thuộc vào việc Công cụ cho nhà phát triển có đang mở hay không. Sau khi bạn mở Công cụ cho nhà phát triển (hoặc đối với mọi ứng dụng CDP khác được đính kèm), bạn có thể phát lại tất cả sự cố đã ghi trước đó qua bộ nhớ.

Quá trình này đã kết thúc công việc phụ trợ và giờ đây, chúng tôi cần tập trung vào cách đưa vấn đề này lên giao diện người dùng.

Bước 5: Thiết kế văn bản vấn đề

Thiết kế văn bản vấn đề là một quá trình có sự tham gia của nhiều nhóm ngoài nhóm của chúng tôi. Ví dụ: chúng tôi thường dựa vào thông tin chi tiết của nhóm triển khai tính năng (trong trường hợp này là nhóm CSP) và tất nhiên là nhóm DevRel, chuyên thiết kế cách thức mà các nhà phát triển web phải xử lý một loại vấn đề nhất định. Thông tin về vấn đề thường được tinh chỉnh lại 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 thảo sơ bộ về những gì họ hình dung:


## 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 ta đã đạt được:

ALT_TEXT_HERE

Như bạn có thể thấy, việc tham gia vào nhóm tính năng và DevRel sẽ giúp nội dung mô tả rõ ràng và chính xác hơn rất nhiều!

Bạn cũng có thể tìm hiểu các vấn đề về CSP trên trang của mình trong thẻ dành riêng cho các trường hợp vi phạm CSP.

Gỡ lỗi sự cố về Loại đáng tin cậy

Khi làm việc với TT ở quy mô lớn, bạn có thể gặp 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ị lượng thông tin ít nhất 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, không có thông tin nào về đối tượng được bao bọc sẽ không hiển thị.

Đó là do 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ị được trả về sẽ không thực sự hữu ích. Thay vào đó, chúng ta muốn có dữ liệu tương tự như những gì 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 để giới thiệu cách xử lý đặc biệt cho các đối tượng loại đáng tin cậy.

Mặc dù vì những lý do lịch sử, việc xử lý tuỳ chỉnh này được thực hiện trong V8, nhưng phương pháp này vẫn 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 kiểu ở cấp JS. Vì V8 là JS thuần tuý nên không thể phân biệt các khái niệm tương ứng với Web API, chẳng hạn như Loại đáng tin cậy. Vì lý do đó, V8 phải nhờ trình nhúng (Blink) trợ giúp phân biệt các trình duyệt này.

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

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

Đột phá 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 trong các trường hợp ngoại lệ của JS. Vì các vi phạm TT được thực thi sẽ kích hoạt ngoại lệ, nên 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 vi phạm TT. Cụ thể, chúng tôi muốn chỉ phân biệt ở chế độ vi phạm TT (không phải các trường hợp ngoại lệ khác), cũng ở chế độ chỉ báo cáo và phân biệt các loại vi phạm TT.

Công cụ cho nhà phát triển đã hỗ trợ nhiều điểm ngắt nên có thể kiến trúc khá dễ mở rộng. Để thêm loại điểm ngắt mới, bạn cần thay đổi phần phụ trợ (Blink), CDP và giao diện người dùng. Chúng ta nên giới thiệu một lệnh CDP mới, gọi là setBreakOnTTViolation. Giao diện người dùng sẽ sử dụng lệnh này để cho phần phụ trợ biết loại vi phạm TT nào cần được vi phạm. Phần phụ trợ, cụ thể là InspectorDOMDebuggerAgent, sẽ cung cấp một "thăm 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, InspectorDOMDebuggerAgent sẽ gửi một thông báo đến giao diện người dùng để tạm dừng quá trình thực thi.

Những việc đã hoàn thành và các bước tiếp theo

Vì các vấn đề được mô tả ở đây được đưa ra, nên thẻ Vấn đề đã trải qua một số thay đổi:

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

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

Hãy cân nhắc việc sử dụng Chrome Canary, Nhà phát triển hoặc Beta làm trình duyệt phát triển mặc định của bạn. Các kênh xem trước này cho phép bạ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, kiểm thử các API nền tảng web tiên tiến và tìm ra các vấn đề trên trang web của bạn trước khi người dùng 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 để thảo luận về các tính năng và thay đổi mới trong bài đăng, hoặc bất kỳ nội dung nào khác liên quan đến Công cụ cho nhà phát triển.

  • 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ông cụ cho nhà phát triển bằng cách sử dụng Tuỳ chọn khác   Thêm > Trợ giúp > Báo cáo vấn đề về Công cụ cho nhà phát triển trong Công cụ cho nhà phát triển.
  • Tweet tại @ChromeDevTools.
  • Để lại bình luận về Tính năng mới của chúng tôi trong Video trên YouTube hoặc Mẹo trong Công cụ cho nhà phát triển Video trên YouTube.