Firefox 148 tăng cường bảo vệ XSS với việc đưa vào setHTML
(hacks.mozilla.org)- Để ngăn chặn tấn công XSS — một trong những lỗ hổng lớn nhất của web — Firefox là trình duyệt đầu tiên hỗ trợ Sanitizer API được chuẩn hóa
- Khi dùng phương thức setHTML() thay cho innerHTML trước đây, HTML không đáng tin cậy sẽ được tự động làm sạch (sanitize) trước khi chèn vào DOM, từ đó loại bỏ script độc hại
- Nếu cấu hình mặc định quá chặt hoặc chưa đủ, nhà phát triển có thể kiểm soát các phần tử và thuộc tính được cho phép thông qua thiết lập tùy chỉnh
- Tính năng này của Firefox khi kết hợp với Trusted Types sẽ nâng cao mức độ bảo mật của web nói chung, đồng thời giúp nhà phát triển có thể ngăn chặn XSS mà không cần một đội ngũ bảo mật riêng
Lỗ hổng XSS và cách Firefox ứng phó
- Cross-site scripting (XSS) xảy ra khi kẻ tấn công chèn HTML hoặc JavaScript tùy ý thông qua nội dung do người dùng nhập
- Kẻ tấn công có thể lợi dụng điều này để theo dõi tương tác của người dùng hoặc đánh cắp dữ liệu
- XSS đã được xếp vào top 3 lỗ hổng web nghiêm trọng (CWE-79) trong gần 10 năm
- Từ năm 2009, Firefox đã dẫn dắt tiêu chuẩn Content-Security-Policy (CSP) để tăng cường phòng vệ trước XSS
- CSP giới hạn các tài nguyên mà website có thể tải và thực thi
- Tuy nhiên, vì đòi hỏi thay đổi cấu trúc website hiện có và rà soát bảo mật liên tục nên việc áp dụng rộng rãi còn hạn chế
Vai trò của Sanitizer API và setHTML()
- Sanitizer API cung cấp một phương thức chuẩn hóa để chuyển đổi HTML độc hại thành dạng vô hại
- Trong ví dụ mã, phần tử `` bị loại bỏ và chỉ còn lại `Hello my name is
`
- Phương thức setHTML() tự động thực hiện quá trình làm sạch khi chèn HTML, bảo đảm hành vi an toàn theo mặc định
- Chỉ cần thay phép gán
innerHTMLhiện tại bằngsetHTML()là đã có thể có cơ chế phòng vệ XSS mạnh mẽ
- Chỉ cần thay phép gán
- Nếu thiết lập mặc định quá nghiêm ngặt hoặc quá lỏng, nhà phát triển có thể định nghĩa các phần tử và thuộc tính HTML được cho phép bằng cấu hình tùy chỉnh
- Có thể dùng công cụ Sanitizer API playground để thử nghiệm
Kết hợp với Trusted Types
- Trusted Types API cung cấp thêm một lớp bảo mật bằng cách kiểm soát tập trung việc phân tích và chèn HTML
- Khi dùng
setHTML(), có thể áp dụng chính sách Trusted Types một cách dễ dàng - Chính sách nghiêm ngặt có thể chỉ cho phép
setHTML()và chặn các cách chèn nguy hiểm khác, góp phần ngăn XSS tái xuất trong tương lai
- Khi dùng
Tác động nâng cao bảo mật trong Firefox 148
- Firefox 148 hỗ trợ cả Sanitizer API và Trusted Types, qua đó nâng cao đáng kể mức bảo mật mặc định
- Nhà phát triển có thể ngăn chặn XSS chỉ với thay đổi mã đơn giản, không cần chính sách bảo mật phức tạp hay đội ngũ bảo mật riêng
- Việc đưa tiêu chuẩn này vào trình duyệt được kỳ vọng sẽ thúc đẩy một môi trường web an toàn hơn trên mọi trình duyệt
Tóm tắt
- Firefox 148 hỗ trợ nhà phát triển web dễ dàng chặn tấn công XSS thông qua phương thức setHTML() và Sanitizer API
- Tính năng này khắc phục các giới hạn của CSP và là bước đệm để phổ biến cách chèn HTML an toàn theo mặc định như một tiêu chuẩn web
- Việc kết hợp với Trusted Types cho phép duy trì bảo mật lâu dài và ngăn XSS tái diễn
- Kết quả là Firefox đang dẫn dắt quá trình chuyển đổi sang một môi trường web nơi bảo mật là mặc định
2 bình luận
Ồ đúng là kiểu này thực sự cần thiết. Nếu được hỗ trợ trên mọi trình duyệt thì có lẽ sẽ tuyệt vời lắm.
Ý kiến trên Hacker News
Những tính năng kiểu này lúc nào cũng hơi đáng lo Vì có sự pha trộn giữa các phương thức xử lý an toàn khi nhận đầu vào người dùng tùy ý và các phương thức không an toàn, nhưng chỉ nhìn tên thì khó phân biệt Lý tưởng nhất là ngay từ đầu, các hàm nguy hiểm phải được thể hiện rõ trong tên gọi Ngoài ra, chính khái niệm “sanitize” HTML cũng khá mơ hồ, và khó đánh giá liệu nó có thực sự an toàn hay không
elementNode.textContentan toàn với đầu vào không đáng tin cậy, cònelementNode.innerHTMLthì không Cái trước escape mọi ký tự, còn cái sau thì không escape gì cả Cũng có ý kiến cho rằng “HTML sanitization” là vấn đề về bản chất không thể giải quyết triệt để Xem thảo luận liên quan ở bình luận này Các API kiểu này lẽ ra không nên được thông qua ngay từ giai đoạn đề xuấtinnerHTMLvàsetHTMLcùng tồn tại, lẽ ra nên loại bỏ hoàn toàninnerHTML, và nếu cần hành vi cũ thì dùngsetHTMLUnsafeinnerHTMLbằng một thiết lập toàn cục Tuy nhiên làm vậy có thể khiến website không hoạt động trên các trình duyệt cũContent-Security-Policy: require-trusted-types-for 'script', thì có thể chặn việc truyền chuỗi thông thường vào các phương thức không có sanitizerNếu như ví dụ cho thấy có thể chèn các thẻ như
hay ` ` vào tên người dùng, thì dù có chặn thực thi script đi nữa vẫn vẫn có thể **tiêm markup tùy ý** Thậm chí còn có thể thay đổi CSS bằng thẻ, ví dụ làm biến đổi giao diện của trang hồ sơ PayPal Điều đó khiến người ta phải tự hỏi ai lại muốn như vậyinnerHTMLmà không phảiinnerTexthaytextContentsetHTMLlà phương án thay thế choinnerHTMLsetHTML()quá chặt hoặc quá lỏng, nhà phát triển có thể cung cấp cấu hình tùy chỉnh để tự định nghĩa các phần tử và thuộc tính HTML được phép", new Sanitizer({})) ``` Làm như vậy sẽ loại bỏ toàn bộ phần tử Cuối cùng thì ở backend vẫn cần sanitize tên người dùng theo cách tiêu chuẩn, và khi xuất ra phải áp dụng HTML escape Theo RFC 2119, đây là yêu cầu ở mức “SHOULD”
Rất vui khi thấy tính năng này xuất hiện, nhưng có lẽ sẽ mất thời gian để mức độ hỗ trợ của trình duyệt đủ phổ biến Có thể kiểm tra tình trạng hỗ trợ trên Can I use
Tiêu đề hơi giật gân một chút Thực ra cũng có thể triển khai sanitization bằng một hàm kiểm tra đầu vào trước khi đưa vào
innerHTMLTuy vậy, những nỗ lực kiểu này rốt cuộc vẫn tạo cảm giác như đang phát minh lại bánh xe Ngoài ra, trên Firefox cũ thì hacks.mozilla.org thậm chí không mở được, còn trên Pale Moon hay SeaMonkey thì MDN bị hiển thị lỗi Cứ như thể “liên minh trình duyệt” đang cố phá hỏng web vậyNếu dùng sai Sanitizer API thì nó có thể trở thành footgun Đặc biệt phải cẩn thận khi dùng chế độ “remove” Tôi nghĩ tốt hơn là chỉ dùng
setText, và hoàn toàn không cho phép người dùng thêm HTMLsetHTMLthì sẽ không phát sinh XSSinnerHTMLđược dùng thường xuyên, rất khó loại bỏ hoàn toànĐiều gây ấn tượng là mọi khía cạnh của truy cập mạng giờ đây đều được kiểm soát đúng cách, nên chuỗi bảo mật đã chuyển từ niềm tin vào mã nguồn sang niềm tin vào cấu hình máy chủ Các giá trị mặc định cũng được thiết lập an toàn
Điều tôi thực sự muốn là một phần tử `` có thể chạy mã nguy hiểm một cách an toàn Không phải sửa mã nguy hiểm, mà là cho phép chạy nó trong môi trường cô lập iframe có hạn chế là không thể chảy cùng DOM, và trong thời đại AI cùng nội dung động ngày càng nhiều, chúng ta cần khả năng đóng gói có thể cấu hợp
Tôi thực sự thích cái tên
setHTMLUnsafeCác tính năng bảo mật sẽ thất bại nếu được thiết kế theo kiểu bắt nhà phát triển phải opt-in Thay vào đó, cách hiệu quả hơn là khiến “con đường nguy hiểm trông thật sự nguy hiểm”Cái tên
set_html()trực quan hơn nhiều so vớiinner_htmlAPI của JavaScript thực sự quá lộn xộn và đến lúc nào đó cần được dọn dẹp Thảo luận lần này tập trung vào bảo mật, nhưng khi công bố API mới thì bản thân thiết kế cũng phải gọn gàngLập trình viên thập niên 90:
Lập trình viên thập niên 2020: