Đảm bảo CSP có khả năng chống lại các cuộc tấn công XSS

Chính sách bảo mật nội dung (CSP) giúp đảm bảo rằng mọi nội dung được tải trong trang đều đáng tin cậy đối với chủ sở hữu trang web. CSP giúp giảm thiểu các cuộc tấn công thông qua tập lệnh trên nhiều trang web (XSS) vì chúng có thể chặn các tập lệnh không an toàn do kẻ tấn công chèn. Tuy nhiên, CSP có thể dễ dàng bị bỏ qua nếu không đủ nghiêm ngặt. Hãy xem bài viết Giảm thiểu tấn công thông qua tập lệnh trên nhiều trang web (XSS) bằng Chính sách bảo mật nội dung (CSP) nghiêm ngặt để biết thêm thông tin. Lighthouse thu thập các CSP được thực thi trên tài liệu chính và báo cáo các vấn đề từ Trình đánh giá CSP nếu có thể bỏ qua các vấn đề đó.

Báo cáo Lighthouse cảnh báo rằng không tìm thấy CSP nào ở chế độ thực thi.
Báo cáo Lighthouse cảnh báo rằng không tìm thấy CSP nào ở chế độ thực thi.

Các phương pháp bắt buộc đối với CSP không thể bỏ qua

Triển khai các phương pháp sau để đảm bảo không thể bỏ qua CSP của bạn. Nếu có thể bỏ qua CSP, Lighthouse sẽ đưa ra cảnh báo mức độ nghiêm trọng cao.

CSP nhắm đến XSS

Để nhắm mục tiêu XSS, CSP phải bao gồm các lệnh script-src, object-srcbase-uri. CSP cũng không được có lỗi cú pháp.

script-srcobject-src bảo vệ trang khỏi các tập lệnh không an toàn và trình bổ trợ không an toàn tương ứng. Ngoài ra, bạn có thể sử dụng default-src để định cấu hình một chính sách rộng thay vì nhiều lệnh, bao gồm cả script-srcobject-src.

base-uri ngăn chặn việc chèn các thẻ <base> trái phép có thể dùng để chuyển hướng tất cả URL tương đối (như tập lệnh) đến một miền do kẻ tấn công kiểm soát.

CSP sử dụng số chỉ dùng một lần hoặc hàm băm để tránh việc bỏ qua danh sách cho phép

Một CSP định cấu hình danh sách cho phép cho script-src dựa trên giả định rằng tất cả các phản hồi đến từ một miền đáng tin cậy đều an toàn và có thể được thực thi dưới dạng tập lệnh. Tuy nhiên, giả định này không đúng với các ứng dụng hiện đại; một số mẫu phổ biến và lành tính như hiển thị giao diện JSONPlưu trữ bản sao của thư viện AngularJS cho phép kẻ tấn công thoát khỏi giới hạn của CSP.

Trong thực tế, mặc dù tác giả ứng dụng có thể không nhận thấy điều này, nhưng hầu hết danh sách cho phép script-src đều có thể bị kẻ tấn công lách bằng lỗi XSS và không bảo vệ được nhiều trước việc chèn tập lệnh. Ngược lại, các phương pháp dựa trên số chỉ dùng một lần và hàm băm không gặp phải những vấn đề này, đồng thời giúp bạn dễ dàng áp dụng và duy trì một chính sách an toàn hơn.

Ví dụ: mã này sử dụng điểm cuối JSONP được lưu trữ trên một miền đáng tin cậy để chèn một tập lệnh do kẻ tấn công kiểm soát:

CSP:

script-src https://trusted.example.com

HTML:

<script src="https://trusted.example.com/path/jsonp?callback=alert(document.domain)//"></script>

Để tránh bị bỏ qua, CSP phải cho phép từng tập lệnh bằng cách sử dụng số chỉ dùng một lần hoặc hàm băm và sử dụng "strict-dynamic" thay vì danh sách cho phép.

Các đề xuất bổ sung về CSP an toàn

Triển khai các phương pháp sau để tăng cường khả năng bảo mật và khả năng tương thích. Nếu CSP không tuân thủ một trong các đề xuất, thì Lighthouse sẽ đưa ra cảnh báo có mức độ nghiêm trọng trung bình.

Định cấu hình tính năng báo cáo của CSP

Việc định cấu hình đích báo cáo sẽ giúp theo dõi mọi sự cố. Bạn có thể đặt đích báo cáo bằng cách sử dụng lệnh report-uri hoặc report-to. report-to hiện không được tất cả trình duyệt hiện đại hỗ trợ. Do đó, bạn nên sử dụng cả hai hoặc chỉ report-uri.

Nếu có nội dung nào vi phạm CSP, trình duyệt sẽ gửi báo cáo đến đích đã định cấu hình. Đảm bảo rằng bạn đã định cấu hình một ứng dụng tại đích đến này để xử lý các báo cáo này.

Xác định CSP trong tiêu đề HTTP

Bạn có thể xác định CSP trong thẻ meta như sau:

<meta http-equiv="Content-Security-Policy" content="script-src 'none'">

Tuy nhiên, bạn nên xác định CSP trong tiêu đề phản hồi HTTP nếu có thể. Thao tác chèn trước thẻ meta sẽ bỏ qua CSP. Ngoài ra, frame-ancestors, sandbox và báo cáo không được hỗ trợ trong CSP thẻ meta.

Đảm bảo CSP có khả năng tương thích ngược

Không phải trình duyệt nào cũng hỗ trợ số chỉ dùng một lần/hàm băm CSP, do đó, bạn nên thêm unsafe-inline làm phương án dự phòng cho các trình duyệt không tuân thủ. Nếu trình duyệt hỗ trợ số chỉ dùng một lần/hàm băm, thì unsafe-inline sẽ bị bỏ qua.

Tương tự, strict-dynamic không được tất cả trình duyệt hỗ trợ. Bạn nên đặt danh sách cho phép làm phương án dự phòng cho mọi trình duyệt không tuân thủ. Danh sách cho phép sẽ bị bỏ qua trong các trình duyệt hỗ trợ strict-dynamic.

Cách phát triển một CSP nghiêm ngặt

Dưới đây là ví dụ về cách sử dụng CSP nghiêm ngặt với chính sách dựa trên số chỉ dùng một lần.

CSP:

script-src 'nonce-random123' 'strict-dynamic' 'unsafe-inline' https:;
object-src 'none';
base-uri 'none';
report-uri https://reporting.example.com;

HTML:

<script nonce="random123" src="https://trusted.example.com/trusted_script.js"></script>

random123 sẽ là bất kỳ chuỗi base64 nào được tạo phía máy chủ mỗi khi trang tải. unsafe-inlinehttps: bị bỏ qua trong các trình duyệt hiện đại do số chỉ dùng một lần và strict-dynamic. Để biết thêm thông tin về việc sử dụng CSP nghiêm ngặt, hãy xem Hướng dẫn về CSP nghiêm ngặt.

Bạn có thể kiểm tra CSP để tìm các cách lách có thể xảy ra bằng Lighthouse và Trình đánh giá CSP. Nếu bạn muốn thử nghiệm một CSP mới mà không có nguy cơ làm hỏng các trang hiện có, hãy xác định CSP ở chế độ chỉ báo cáo bằng cách sử dụng Content-Security-Policy-Report-Only làm tên tiêu đề. Thao tác này sẽ gửi các lỗi vi phạm CSP đến mọi đích báo cáo mà bạn đã định cấu hình bằng report-toreport-uri, nhưng sẽ không thực sự thực thi CSP.