Mô hình bảo mật của web bắt nguồn từ chính sách cùng nguồn gốc. Mã từ https://mybank.com
chỉ nên có quyền truy cập vào dữ liệu của https://mybank.com
và https://evil.example.com
chắc chắn không được phép truy cập.
Mỗi nguồn gốc được tách biệt với phần còn lại của web, cung cấp cho các nhà phát triển một hộp cát an toàn để tạo và chơi. Về lý thuyết, đây là mức giá hoàn hảo. Trên thực tế, những kẻ tấn công đã tìm được những cách tinh vi để phá vỡ hệ thống.
Tấn công tập lệnh trên nhiều trang web (XSS), chẳng hạn như bỏ qua cùng một chính sách nguồn gốc bằng cách lừa một trang web phân phối mã độc hại cùng với nội dung mong muốn. Đây là một vấn đề lớn vì các trình duyệt tin tưởng rằng tất cả mã xuất hiện trên trang là một phần hợp pháp của nguồn gốc bảo mật của trang đó. Bản tóm tắt về XSS là một mặt cắt cũ nhưng mang tính đại diện cho các phương thức mà kẻ tấn công có thể sử dụng để vi phạm niềm tin này bằng cách chèn mã độc hại. Nếu kẻ tấn công chèn thành công bất kỳ mã nào, thì mọi việc đã kết thúc: dữ liệu phiên hoạt động của người dùng bị xâm phạm và thông tin cần được giữ bí mật sẽ bị đánh cắp vào The BadGuys. Hiển nhiên, chúng tôi muốn ngăn điều này nếu có thể.
Phần tổng quan này nêu bật một biện pháp bảo vệ có thể làm giảm đáng kể nguy cơ và tác động của các cuộc tấn công XSS trong các trình duyệt hiện đại: Chính sách bảo mật nội dung (CSP).
TL;DR
- Sử dụng danh sách cho phép để cho khách hàng biết những nội dung được phép và không được phép.
- Tìm hiểu xem có những lệnh nào.
- Tìm hiểu các từ khoá mà họ dùng.
- Mã cùng dòng và
eval()
bị coi là có hại. - Hãy báo cáo các lỗi vi phạm chính sách cho máy chủ của bạn trước khi thực thi.
Danh sách nguồn được cho phép
Vấn đề bị các cuộc tấn công XSS khai thác là trình duyệt không thể phân biệt được tập lệnh thuộc ứng dụng của bạn và tập lệnh đã bị bên thứ ba chèn độc hại. Ví dụ: nút Google +1 ở cuối trang này sẽ tải và thực thi mã từ https://apis.google.com/js/plusone.js
trong bối cảnh nguồn gốc của trang này. Chúng tôi tin tưởng mã đó, nhưng chúng tôi không thể kỳ vọng trình duyệt tự tìm ra mã từ apis.google.com
là tuyệt vời, trong khi mã từ apis.evil.example.com
thì có lẽ không. Trình duyệt sẵn sàng tải xuống và thực thi bất kỳ mã nào mà trang yêu cầu, bất kể nguồn là nguồn.
Thay vì tin tưởng một cách mù quáng vào mọi thứ mà máy chủ phân phối, CSP sẽ xác định tiêu đề HTTP Content-Security-Policy
. Tiêu đề này cho phép bạn tạo danh sách cho phép các nguồn nội dung đáng tin cậy, đồng thời hướng dẫn trình duyệt chỉ thực thi hoặc hiển thị tài nguyên từ các nguồn đó. Ngay cả khi kẻ tấn công có thể tìm thấy một lỗ hổng để chèn tập lệnh, tập lệnh sẽ không khớp với danh sách cho phép nên sẽ không được thực thi.
Vì chúng ta tin tưởng apis.google.com
sẽ cung cấp mã hợp lệ và chúng ta tin tưởng chính mình cũng làm như vậy, hãy xác định một chính sách chỉ cho phép tập lệnh thực thi khi tập lệnh đến từ một trong hai nguồn đó:
Content-Security-Policy: script-src 'self' https://apis.google.com
Đơn giản, phải không? Như bạn có thể đoán, script-src
là một lệnh kiểm soát một tập hợp các đặc quyền liên quan đến tập lệnh cho một trang cụ thể. Chúng tôi đã chỉ định 'self'
làm một nguồn tập lệnh hợp lệ và https://apis.google.com
là một nguồn khác. Trình duyệt sẽ tải xuống và thực thi JavaScript nghiêm ngặt từ apis.google.com
qua HTTPS, cũng như từ nguồn gốc của trang hiện tại.
Với chính sách này được xác định, trình duyệt chỉ cần báo lỗi thay vì tải tập lệnh từ bất kỳ nguồn nào khác. Khi một kẻ tấn công thông minh chèn mã vào trang web của bạn, chúng sẽ gặp phải thông báo lỗi thay vì thành công như mong đợi.
Chính sách áp dụng cho nhiều loại tài nguyên
Mặc dù tài nguyên tập lệnh là rủi ro bảo mật rõ ràng nhất, nhưng CSP cũng cung cấp một bộ lệnh chính sách phong phú cho phép kiểm soát tương đối chi tiết các tài nguyên mà một trang được phép tải. Bạn đã thấy script-src
nên khái niệm này phải rõ ràng.
Hãy xem nhanh các lệnh còn lại về tài nguyên. Danh sách dưới đây thể hiện trạng thái của các lệnh ở cấp độ 2. Thông số kỹ thuật cấp 3 đã được phát hành, nhưng phần lớn chưa được triển khai trong các trình duyệt chính.
base-uri
hạn chế những URL có thể xuất hiện trong phần tử<base>
của trang.child-src
liệt kê các URL của trình thực thi và nội dung khung được nhúng. Ví dụ:child-src https://youtube.com
sẽ cho phép nhúng video từ YouTube chứ không cho phép nhúng video từ các nguồn khác.connect-src
giới hạn các nguồn gốc mà bạn có thể kết nối (thông qua XHR, WebSockets và EventSource).font-src
chỉ định những nguồn gốc có thể phân phát phông chữ web. Bạn có thể bật phông chữ web của Google thông quafont-src https://themes.googleusercontent.com
.form-action
liệt kê các điểm cuối hợp lệ để gửi từ thẻ<form>
.frame-ancestors
chỉ định các nguồn có thể nhúng trang hiện tại. Lệnh này áp dụng cho các thẻ<frame>
,<iframe>
,<embed>
và<applet>
. Bạn không thể sử dụng lệnh này trong thẻ<meta>
và chỉ áp dụng cho các tài nguyên không phải HTML.frame-src
không còn được dùng ở cấp 2 nhưng được khôi phục ở cấp 3. Nếu không, giá trị này vẫn sẽ quay vềchild-src
như trước.img-src
xác định nguồn gốc mà hình ảnh có thể được tải.media-src
hạn chế các nguồn gốc được phép phân phối video và âm thanh.object-src
cho phép kiểm soát Flash và các trình bổ trợ khác.plugin-types
giới hạn các loại trình bổ trợ mà một trang có thể gọi.report-uri
chỉ định một URL mà trình duyệt sẽ gửi báo cáo khi vi phạm chính sách bảo mật nội dung. Bạn không thể sử dụng lệnh này trong các thẻ<meta>
.style-src
là đối tác củascript-src
cho biểu định kiểu.upgrade-insecure-requests
hướng dẫn các tác nhân người dùng ghi lại các giao thức URL, thay đổi HTTP thành HTTPS. Lệnh này dành cho các trang web có số lượng lớn URL cũ cần được viết lại.worker-src
là một lệnh CSP cấp 3 nhằm hạn chế những URL có thể được tải dưới dạng một trình thực thi, một trình thực thi dùng chung hoặc trình thực thi dịch vụ. Kể từ tháng 7 năm 2017, lệnh này đã được triển khai có giới hạn.
Theo mặc định, các lệnh được mở rộng. Nếu bạn không đặt một chính sách cụ thể cho một lệnh, giả sử font-src
, thì lệnh đó sẽ hoạt động theo mặc định như thể bạn đã chỉ định *
làm nguồn hợp lệ (ví dụ: bạn có thể tải phông chữ từ bất cứ đâu mà không bị hạn chế).
Bạn có thể ghi đè hành vi mặc định này bằng cách chỉ định lệnh default-src
. Lệnh này xác định các giá trị mặc định cho hầu hết các lệnh mà bạn không chỉ định. Nhìn chung, nguyên tắc này áp dụng cho mọi lệnh kết thúc bằng -src
. Nếu default-src
được đặt thành https://example.com
và bạn không chỉ định được lệnh font-src
, thì bạn có thể tải phông chữ từ https://example.com
chứ không phải ở nơi nào khác. Chúng tôi chỉ xác định script-src
trong các ví dụ trước đó, tức là hình ảnh, phông chữ, v.v. có thể tải từ mọi nguồn.
Các lệnh sau đây không dùng default-src
làm phương án dự phòng. Hãy nhớ rằng việc không đặt chúng cũng giống như việc cho phép bất cứ điều gì.
base-uri
form-action
frame-ancestors
plugin-types
report-uri
sandbox
Bạn có thể sử dụng (nhiều hoặc ít lệnh trong số này) sao cho phù hợp với ứng dụng cụ thể, chỉ cần liệt kê từng lệnh trong tiêu đề HTTP, phân tách các lệnh bằng dấu chấm phẩy. Hãy nhớ liệt kê tất cả các tài nguyên cần thiết thuộc một loại cụ thể trong một lệnh duy nhất. Nếu bạn đã viết
nội dung như script-src https://host1.com; script-src https://host2.com
,
lệnh thứ hai sẽ bị bỏ qua. Ví dụ sau sẽ chỉ định chính xác cả hai nguồn gốc là hợp lệ:
script-src https://host1.com https://host2.com
Chẳng hạn, nếu bạn có một ứng dụng tải tất cả tài nguyên của ứng dụng đó từ một mạng phân phối nội dung (chẳng hạn như https://cdn.example.net
) và biết rằng bạn không cần bất kỳ nội dung hoặc trình bổ trợ khung nào, thì chính sách của bạn có thể sẽ có dạng như sau:
Content-Security-Policy: default-src https://cdn.example.net; child-src 'none'; object-src 'none'
Thông tin triển khai
Bạn sẽ thấy các tiêu đề X-WebKit-CSP
và X-Content-Security-Policy
trong nhiều hướng dẫn trên web. Từ giờ trở đi, bạn nên bỏ qua các tiêu đề có tiền tố này. Các trình duyệt hiện đại (ngoại trừ IE) hỗ trợ tiêu đề Content-Security-Policy
chưa có tiền tố. Đó là tiêu đề mà bạn nên sử dụng.
Bất kể bạn dùng tiêu đề nào, chính sách đều được xác định theo từng trang: bạn cần phải gửi tiêu đề HTTP cùng với mọi phản hồi mà bạn muốn đảm bảo được bảo vệ. Điều này mang lại tính linh hoạt cao vì bạn có thể tinh chỉnh chính sách cho các trang cụ thể dựa trên nhu cầu cụ thể của các trang đó. Có thể một nhóm các trang trong trang web của bạn có nút +1, trong khi một số trang khác thì không: bạn chỉ có thể cho phép mã nút được tải khi cần.
Danh sách nguồn trong mỗi lệnh có thể linh hoạt. Bạn có thể chỉ định các nguồn theo giao thức (data:
, https:
) hoặc mức độ cụ thể từ chỉ tên máy chủ (example.com
, khớp với mọi nguồn gốc trên máy chủ lưu trữ đó: giao thức bất kỳ, cổng bất kỳ) đến URI đủ điều kiện (https://example.com:443
, chỉ khớp HTTPS, chỉ example.com
và chỉ cổng 443). Chấp nhận ký tự đại diện, nhưng chỉ dưới dạng lược đồ, cổng hoặc ở vị trí ngoài cùng bên trái của tên máy chủ: *://*.example.com:*
sẽ khớp với mọi miền con của example.com
(nhưng không phải example.com
), bằng cách sử dụng bất kỳ lược đồ nào trên bất kỳ cổng nào.
Danh sách nguồn cũng chấp nhận 4 từ khoá:
'none'
, như bạn có thể mong đợi, không khớp gì.'self'
khớp với nguồn gốc hiện tại nhưng không khớp với các miền con của miền đó.'unsafe-inline'
cho phép JavaScript và CSS cùng dòng. (Chúng ta sẽ đề cập đến điều này chi tiết hơn một chút.)'unsafe-eval'
cho phép các cơ chế chuyển văn bản sang JavaScript nhưeval
. (Chúng ta cũng sẽ xem xét mục này.)
Những từ khoá này yêu cầu phải đặt một dấu ngoặc đơn. Ví dụ: script-src 'self'
(có dấu ngoặc kép) cho phép thực thi JavaScript từ máy chủ hiện tại; script-src self
(không có dấu ngoặc kép) cho phép JavaScript từ máy chủ có tên "self
" (và không phải từ máy chủ hiện tại), điều này có thể không đúng ý bạn.
Hộp cát
Có một lệnh nữa đáng nói, đó là sandbox
. Báo cáo này hơi khác với những mục khác mà chúng tôi đã xem xét, vì nó đặt ra hạn chế về các thao tác mà trang có thể thực hiện thay vì các tài nguyên mà trang có thể tải. Nếu có lệnh sandbox
, trang sẽ được xử lý như thể trang được tải bên trong <iframe>
bằng thuộc tính sandbox
. Điều này có thể có nhiều hiệu quả trên trang: buộc trang xác định một nguồn gốc duy nhất và ngăn việc gửi biểu mẫu, v.v. Nội dung này nằm ngoài phạm vi của bài viết này một chút, nhưng bạn có thể tìm thấy đầy đủ thông tin chi tiết về các thuộc tính hộp cát hợp lệ trong phần "Hộp cát" của thông số kỹ thuật HTML5.
Thẻ meta
Cơ chế phân phối ưu tiên của CSP là một tiêu đề HTTP. Tuy nhiên, bạn nên đặt chính sách trên một trang ngay trong mã đánh dấu. Hãy thực hiện việc đó bằng cách sử dụng thẻ <meta>
có thuộc tính http-equiv
:
<meta
http-equiv="Content-Security-Policy"
content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'"
/>
Bạn không thể sử dụng thuộc tính này cho frame-ancestors
, report-uri
hoặc sandbox
.
Mã cùng dòng bị coi là có hại
Rõ ràng là CSP được dựa trên nguồn gốc của danh sách cho phép, vì đó là một cách rõ ràng để hướng dẫn trình duyệt xử lý các nhóm tài nguyên cụ thể là có thể chấp nhận được và từ chối phần còn lại. Tuy nhiên, danh sách cho phép dựa trên nguồn gốc không giải quyết được mối đe doạ lớn nhất do các cuộc tấn công XSS: chèn tập lệnh cùng dòng.
Nếu kẻ tấn công có thể chèn thẻ tập lệnh trực tiếp chứa một số tải trọng độc hại (<script>sendMyDataToEvilDotCom();</script>
), thì trình duyệt không có cơ chế nào để phân biệt thẻ này với thẻ tập lệnh nội tuyến hợp pháp. CSP giải quyết vấn đề này bằng cách cấm hoàn toàn tập lệnh cùng dòng:
đây là cách duy nhất để đảm bảo an toàn.
Lệnh cấm này không chỉ bao gồm các tập lệnh được nhúng trực tiếp trong thẻ script
mà còn áp dụng cho cả các trình xử lý sự kiện nội tuyến và URL javascript:
. Bạn cần di chuyển nội dung của các thẻ script
vào một tệp bên ngoài và thay thế các URL javascript:
và <a ... onclick="[JAVASCRIPT]">
bằng các lệnh gọi addEventListener()
thích hợp. Ví dụ: bạn có thể viết lại nội dung sau từ:
<script>
function doAmazingThings() {
alert('YOU AM AMAZING!');
}
</script>
<button onclick="doAmazingThings();">Am I amazing?</button>
thành các thông tin chi tiết hơn như:
<!-- amazing.html -->
<script src="amazing.js"></script>
<button id="amazing">Am I amazing?</button>
<div style="clear:both;"></div>
// amazing.js
function doAmazingThings() {
alert('YOU AM AMAZING!');
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('amazing').addEventListener('click', doAmazingThings);
});
Mã được viết lại có một số ưu điểm, cả trên và ngoài việc kết hợp hiệu quả với CSP. Đây là phương pháp hay nhất, bất kể bạn sử dụng CSP nào. JavaScript nội tuyến kết hợp cấu trúc và hành vi theo chính xác cách bạn không nên làm. Tài nguyên bên ngoài giúp trình duyệt dễ dàng lưu vào bộ nhớ đệm, dễ hiểu hơn đối với nhà phát triển, đồng thời tạo điều kiện cho quá trình biên dịch và giảm thiểu. Bạn sẽ viết mã tốt hơn nếu bạn xử lý xong việc di chuyển mã vào tài nguyên bên ngoài.
Kiểu cùng dòng được xử lý theo cách tương tự: cả thuộc tính style
và thẻ style
phải được hợp nhất vào các biểu định kiểu bên ngoài để ngăn chặn các phương thức đánh cắp dữ liệu thông minh một cách đáng kinh ngạc mà CSS cho phép.
Nếu phải có tập lệnh và kiểu cùng dòng, bạn có thể bật tập lệnh này bằng cách thêm 'unsafe-inline'
làm nguồn được phép theo lệnh script-src
hoặc style-src
. Bạn cũng có thể sử dụng số chỉ dùng một lần hoặc hàm băm (xem bên dưới), nhưng thực sự không nên dùng.
Cấm tập lệnh cùng dòng là cách bảo mật lớn nhất mà CSP cung cấp, đồng thời, việc cấm kiểu cùng dòng cũng sẽ làm cứng ứng dụng của bạn. Bạn cần nỗ lực một chút để đảm bảo mọi thứ hoạt động chính xác sau khi di chuyển tất cả mã ra ngoài dòng, nhưng đó là một sự đánh đổi cũng đáng giá.
Nếu bạn bắt buộc phải sử dụng
CSP cấp 2 cung cấp khả năng tương thích ngược cho các tập lệnh cùng dòng bằng cách cho phép bạn thêm các tập lệnh cùng dòng cụ thể vào danh sách cho phép bằng cách sử dụng số chỉ dùng một lần mật mã (số dùng một lần) hoặc hàm băm. Mặc dù việc này có thể rườm rà, nhưng sẽ hữu ích khi cần.
Để sử dụng số chỉ dùng một lần, hãy cung cấp thuộc tính số chỉ dùng một lần cho thẻ tập lệnh của bạn. Giá trị của nguồn này phải khớp với một giá trị trong danh sách các nguồn đáng tin cậy. Ví dụ:
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
// Some inline code I can't remove yet, but need to asap.
</script>
Bây giờ, hãy thêm số chỉ dùng một lần vào lệnh script-src
được thêm vào từ khoá nonce-
.
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
Hãy nhớ rằng nonces phải được tạo lại cho mọi yêu cầu trang và phải không xác định được.
Hàm băm hoạt động theo cách tương tự. Thay vì thêm mã vào thẻ tập lệnh, hãy tạo hàm băm SHA của chính tập lệnh rồi thêm mã đó vào lệnh script-src
.
Ví dụ: giả sử trang của bạn chứa:
<script>
alert('Hello, world.');
</script>
Chính sách của bạn sẽ bao gồm:
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='
Có một vài điều cần lưu ý ở đây. Tiền tố sha*-
chỉ định thuật toán tạo ra hàm băm. Trong ví dụ trên, sha256-
được sử dụng. CSP cũng hỗ trợ sha384-
và sha512-
. Khi tạo hàm băm, đừng thêm thẻ <script>
. Ngoài ra, cách viết hoa và khoảng trắng cũng quan trọng, bao gồm cả khoảng trắng ở đầu hoặc ở cuối.
Khi tìm kiếm trên Google về cách tạo hàm băm SHA, bạn sẽ tìm thấy các giải pháp bằng nhiều ngôn ngữ. Khi sử dụng Chrome 40 trở lên, bạn có thể mở Công cụ cho nhà phát triển rồi tải lại trang của mình. Thẻ Console sẽ chứa các thông báo lỗi có hàm băm sha256 chính xác cho từng tập lệnh cùng dòng.
Eval nữa
Ngay cả khi kẻ tấn công không thể chèn tập lệnh trực tiếp, chúng vẫn có thể lừa ứng dụng của bạn chuyển đổi văn bản thô thành JavaScript có thể thực thi và thay mặt chúng thực thi tập lệnh đó. eval()
, new Function() , setTimeout([string], ...)
và setInterval([string], ...)
đều là các vectơ mà qua đó văn bản được chèn có thể thực thi một nội dung độc hại không mong muốn. Phản hồi mặc định của CSP đối với rủi ro này là chặn hoàn toàn tất cả các vectơ này.
Vấn đề này có nhiều tác động đến cách bạn xây dựng ứng dụng:
- Bạn phải phân tích cú pháp JSON thông qua
JSON.parse
tích hợp sẵn, thay vì dựa vàoeval
. Thao tác JSON gốc có sẵn trên mọi trình duyệt kể từ IE8 và hoàn toàn an toàn. - Viết lại bất kỳ lệnh gọi
setTimeout
hoặcsetInterval
nào mà bạn đang thực hiện bằng các hàm cùng dòng thay vì chuỗi. Ví dụ:
setTimeout("document.querySelector('a').style.display = 'none';", 10);
sẽ được viết tốt hơn là:
setTimeout(function () {
document.querySelector('a').style.display = 'none';
}, 10);
- Tránh tạo mẫu cùng dòng trong thời gian chạy: Nhiều thư viện tạo mẫu sử dụng
new Function()
thoải mái để tăng tốc độ tạo mẫu trong thời gian chạy. Đây là một ứng dụng lập trình động tiện lợi, nhưng có rủi ro về việc đánh giá văn bản độc hại. Một số khung hỗ trợ CSP ngay từ đầu, sẽ quay lại sử dụng trình phân tích cú pháp mạnh mẽ khi không cóeval
. Lệnh ng-csp của AngularJS là một ví dụ điển hình về trường hợp này.
Tuy nhiên, lựa chọn tốt hơn là ngôn ngữ mẫu có khả năng tổng hợp (ví dụ: Thanh điều khiển có). Việc biên dịch trước các mẫu có thể giúp trải nghiệm người dùng thậm chí nhanh hơn so với cách triển khai nhanh nhất trong thời gian chạy và cách này cũng an toàn hơn. Nếu eval và các anh em chuyển văn bản sang JavaScript cần thiết cho ứng dụng của mình, thì bạn có thể bật chúng bằng cách thêm 'unsafe-eval'
làm nguồn được phép theo lệnh script-src
, nhưng bạn không nên làm như vậy. Việc cấm khả năng thực thi các chuỗi sẽ khiến kẻ tấn công khó thực thi mã trái phép trên trang web của bạn hơn.
Báo cáo
Khả năng chặn các tài nguyên không đáng tin cậy ở phía máy khách của CSP là một lợi ích to lớn cho người dùng. Tuy nhiên, sẽ rất hữu ích nếu bạn gửi lại một số loại thông báo về máy chủ để có thể xác định và loại bỏ mọi lỗi cho phép chèn độc hại ngay từ đầu. Để đạt được mục tiêu này, bạn có thể hướng dẫn trình duyệt gửi các báo cáo vi phạm theo định dạng JSON POST
đến một vị trí được chỉ định trong lệnh report-uri
.
Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
Các báo cáo đó sẽ trông giống như sau:
{
"csp-report": {
"document-uri": "http://example.org/page.html",
"referrer": "http://evil.example.com/",
"blocked-uri": "http://evil.example.com/evil.js",
"violated-directive": "script-src 'self' https://apis.google.com",
"original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser"
}
}
Tệp này chứa nhiều thông tin hữu ích giúp bạn theo dõi nguyên nhân cụ thể của lỗi vi phạm, bao gồm cả trang xảy ra lỗi vi phạm (document-uri
), đường liên kết giới thiệu của trang đó (lưu ý rằng không giống như trường tiêu đề HTTP, khoá không bị viết sai chính tả), tài nguyên vi phạm chính sách của trang (blocked-uri
), lệnh cụ thể mà trang đó vi phạm (violated-directive
) và chính sách hoàn chỉnh của trang (original-policy
).
Chỉ báo cáo
Nếu mới bắt đầu sử dụng CSP, bạn nên đánh giá trạng thái hiện tại của ứng dụng trước khi triển khai một chính sách hà nội cho người dùng.
Để là bước đệm cho việc triển khai hoàn chỉnh, bạn có thể yêu cầu trình duyệt giám sát một chính sách, báo cáo các trường hợp vi phạm nhưng không thực thi các quy định hạn chế đó. Thay vì gửi tiêu đề Content-Security-Policy
, hãy gửi tiêu đề Content-Security-Policy-Report-Only
.
Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
Chính sách được chỉ định ở chế độ chỉ báo cáo sẽ không chặn tài nguyên bị hạn chế, nhưng sẽ gửi báo cáo vi phạm đến vị trí mà bạn chỉ định. Bạn thậm chí có thể gửi cả hai tiêu đề, thực thi một chính sách trong khi theo dõi một chính sách khác. Đây là một cách hiệu quả để đánh giá tác động của các thay đổi đối với CSP của ứng dụng: bật tính năng báo cáo về một chính sách mới, theo dõi các báo cáo về lỗi vi phạm và khắc phục mọi lỗi xuất hiện; khi bạn hài lòng với hiệu quả của chính sách này, hãy bắt đầu thực thi chính sách mới.
Sử dụng trong thế giới thực
CSP 1 khá hữu ích trên Chrome, Safari và Firefox, nhưng hỗ trợ rất hạn chế trong IE 10. Bạn có thể xem thông tin cụ thể tại caniuse.com. CSP cấp 2 đã có trong Chrome kể từ phiên bản 40. Các trang web lớn như Twitter và Facebook đã triển khai tiêu đề (nghiên cứu điển hình của Twitter rất đáng để đọc) và tiêu chuẩn này đã sẵn sàng để bạn bắt đầu triển khai trên các trang web của mình.
Bước đầu tiên để tạo chính sách cho ứng dụng là đánh giá các tài nguyên mà bạn thực sự tải. Khi bạn nghĩ mình đã hiểu rõ cách mọi thứ được tổng hợp trong ứng dụng, hãy thiết lập một chính sách dựa trên các yêu cầu đó. Hãy cùng xem qua một số trường hợp sử dụng phổ biến và xác định cách chúng ta có thể hỗ trợ tốt nhất các trường hợp này trong phạm vi bảo vệ của CSP.
Trường hợp sử dụng 1: tiện ích mạng xã hội
Nút +1 của Google bao gồm một tập lệnh từ
https://apis.google.com
và nhúng<iframe>
từhttps://plusone.google.com
. Bạn cần có một chính sách bao gồm cả hai nguồn này để nhúng nút. Chính sách tối thiểu sẽ làscript-src https://apis.google.com; child-src https://plusone.google.com
. Bạn cũng cần đảm bảo rằng đoạn mã JavaScript mà Google cung cấp được kéo vào một tệp JavaScript bên ngoài. Nếu bạn có chính sách ở Cấp 1 sử dụngframe-src
Cấp 2 yêu cầu bạn phải thay đổi chính sách đó thànhchild-src
. Điều này không còn cần thiết trong CSP cấp 3 nữa.Nút Thích của Facebook có một số cách triển khai. Bạn nên sử dụng phiên bản
<iframe>
vì phiên bản này được tạo hộp cát an toàn từ phần còn lại của trang web. Phương thức này cần có lệnhchild-src https://facebook.com
để hoạt động đúng cách. Xin lưu ý rằng, theo mặc định, mã<iframe>
mà Facebook cung cấp sẽ tải một URL tương đối là//facebook.com
. Hãy thay đổi chế độ cài đặt đó để chỉ định rõ HTTPS:https://facebook.com
. Không có lý do gì để sử dụng HTTP nếu bạn không cần phải làm vậy.Nút Tweet của Twitter dựa vào quyền truy cập vào tập lệnh và một khung, cả hai đều được lưu trữ tại
https://platform.twitter.com
. (Twitter cũng cung cấp URL tương đối theo mặc định; hãy chỉnh sửa mã để chỉ định HTTPS khi sao chép/dán mã cục bộ). Bạn đã hoàn tấtscript-src https://platform.twitter.com; child-src https://platform.twitter.com
, miễn là bạn di chuyển đoạn mã JavaScript mà Twitter cung cấp vào một tệp JavaScript bên ngoài.Các nền tảng khác có yêu cầu tương tự và có thể được giải quyết tương tự. Bạn chỉ nên đặt
default-src
với giá trị'none'
và xem bảng điều khiển để xác định những tài nguyên cần bật để giúp các tiện ích hoạt động.
Việc bao gồm nhiều tiện ích rất đơn giản: chỉ cần kết hợp các lệnh chính sách, nhớ hợp nhất tất cả các tài nguyên của một loại thành một lệnh duy nhất. Nếu bạn muốn dùng cả 3 tiện ích mạng xã hội, chính sách sẽ có dạng như sau:
script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com
Trường hợp sử dụng 2: khoá
Giả sử trong giây lát, bạn điều hành một trang web về ngân hàng và muốn đảm bảo rằng
chỉ những tài nguyên mà bạn tự viết mới có thể tải được. Trong trường hợp này, hãy bắt đầu bằng một chính sách mặc định chặn hoàn toàn mọi thứ (default-src 'none'
) và thiết lập từ đó.
Giả sử ngân hàng tải tất cả hình ảnh, kiểu và tập lệnh từ CDN tại https://cdn.mybank.net
và kết nối qua XHR với https://api.mybank.com/
để kéo xuống nhiều bit dữ liệu khác nhau. Khung được sử dụng, nhưng chỉ cho các trang cục bộ trên trang web (không có nguồn gốc của bên thứ ba). Trang web không có Flash, không có phông chữ, không có bổ sung. Tiêu đề CSP hạn chế nhất mà chúng tôi có thể gửi là:
Content-Security-Policy: default-src 'none'; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; child-src 'self'
Trường hợp sử dụng 3: Chỉ SSL
Quản trị viên của diễn đàn thảo luận về đám cưới muốn đảm bảo rằng tất cả tài nguyên chỉ được tải qua các kênh bảo mật mà không thực sự viết nhiều mã; việc viết lại phần lớn phần mềm diễn đàn của bên thứ ba chứa đầy tập lệnh và kiểu nội tuyến vượt quá khả năng của anh ấy. Chính sách sau đây sẽ có hiệu lực:
Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'
Mặc dù https:
được chỉ định trong default-src
, nhưng tập lệnh và lệnh kiểu không tự động kế thừa nguồn đó. Mỗi lệnh sẽ ghi đè hoàn toàn giá trị mặc định cho loại tài nguyên cụ thể đó.
Tương lai
Chính sách bảo mật nội dung cấp 2 là Đề xuất cho ứng viên. Nhóm làm việc về bảo mật ứng dụng web của W3C đã bắt đầu làm việc với phiên bản tiếp theo của quy cách, Chính sách bảo mật nội dung cấp 3.
Nếu bạn muốn thảo luận về các tính năng sắp ra mắt này, hãy xem qua bản lưu trữ danh sách gửi thư public-webappsec@ hoặc tự tham gia.