4 điểm bởi GN⁺ 2024-09-02 | 1 bình luận | Chia sẻ qua WhatsApp
  • Web clipboard có thể lưu dữ liệu đã sao chép dưới nhiều biểu diễn MIME cùng lúc, để mỗi ứng dụng chọn đúng định dạng mình cần khi dán
  • Async Clipboard API bị giới hạn chủ yếu ở text/plain, text/html, image/png, nên các kiểu tùy chỉnh như application/json sẽ bị từ chối ghi vì lý do bảo mật
  • Clipboard Events API cũ có thể xử lý chuỗi kiểu dữ liệu tùy ý, nhưng clipboard hệ thống thực tế chỉ thay đổi trong sự kiện người dùng đáng tin cậy
  • Google Docs tạo sự kiện copy đáng tin cậy bằng execCommand("copy"), còn Figma nhúng dữ liệu tùy chỉnh vào thuộc tính HTML base64 để xử lý sao chép giữa trình duyệt và ứng dụng native
  • Web Custom Formats mở ra kiểu tùy chỉnh cho async Clipboard API bằng tiền tố "web ", nhưng cần trình duyệt dựa trên Chromium và ứng dụng native đã được cập nhật

Mô hình cơ bản của web clipboard

  • Clipboard có thể lưu nhiều biểu diễn (representation) cho một thao tác sao chép, kèm theo kiểu MIME
    • text/plain: văn bản thuần
    • text/html: HTML
    • image/png: ảnh PNG
  • Google Docs đọc biểu diễn text/html để giữ nguyên định dạng như liên kết, cỡ chữ, màu sắc
  • Các ứng dụng chỉ cần văn bản gốc như VS Code thì chỉ cần đọc biểu diễn text/plain

Giới hạn kiểu của async Clipboard API

  • navigator.clipboard.read() kiểm tra types của mục clipboard rồi đọc một biểu diễn cụ thể như getType("text/html")
  • navigator.clipboard.write() có thể ghi nhiều Blob cùng lúc trong một ClipboardItem, với khóa là kiểu MIME
  • Nếu thử ghi application/json bằng ClipboardItem, sẽ phát sinh ngoại lệ Type application/json not supported on write
  • Đặc tả Clipboard của W3C yêu cầu write từ chối các kiểu khác ngoài text/plain, text/html, image/png
  • application/json từng nằm trong danh sách kiểu dữ liệu bắt buộc từ năm 2012 đến 2021, nhưng đã bị xóa trong w3c/clipboard-apis#155
    • Trước thay đổi này, danh sách kiểu dữ liệu bắt buộc gồm 16 kiểu cho đọc và 8 kiểu cho ghi
    • Danh sách bị rút gọn vì các trình duyệt không hỗ trợ nhiều kiểu bắt buộc do lo ngại bảo mật
  • Đặc tả cảnh báo rằng script không đáng tin cậy có thể đưa vào clipboard dữ liệu gây khai thác lỗ hổng phần mềm cục bộ, nên các kiểu được phép bị giới hạn

Clipboard Events API và isTrusted

  • ClipboardEvent phát sinh trong các sự kiện copy, cut, paste và cung cấp đối tượng DataTransfer qua thuộc tính clipboardData
  • Trong sự kiện copy, có thể ghi dữ liệu bằng e.clipboardData.setData("text/plain", "..."), setData("text/html", "...")
  • Trong sự kiện paste, có thể đọc biểu diễn HTML bằng e.clipboardData.getData("text/html")
  • clipboardData.setData("application/json", json) không ném ngoại lệ, và trong handler paste cũng có thể thấy kiểu application/json cùng chuỗi JSON
  • clipboardData là giao diện cũ hơn rất nhiều so với async Clipboard API
    • Async Clipboard API được thêm vào đặc tả năm 2017
    • clipboardData, setData, getData đã xuất hiện trong bản nháp W3C từ năm 2006
    • Bản nháp đó phản ánh đáng kể các tính năng đã được triển khai trong Internet Explorer
    • Internet Explorer 4 phát hành năm 1997, nên giao diện clipboardData có thể xem là đã tồn tại ít nhất 26 năm tại thời điểm bài viết được viết
  • Từ đặc tả năm 2011 mới có kiểu MIME, nhưng đặc tính cho phép truyền bất kỳ chuỗi nào làm đối số kiểu cho setData() vẫn được giữ đến nay
  • Event.isTrusted là thuộc tính chỉ đọc, chỉ có giá trị true khi sự kiện được tạo bởi user agent
    • Sự kiện copy khi người dùng nhấn Command+C có isTrustedtrue
    • Sự kiện tổng hợp tạo bằng dispatchEvent()isTrustedfalse
  • Các sự kiện copy/cut tổng hợp không thể sửa clipboard hệ thống, còn sự kiện paste tổng hợp không thể truy cập dữ liệu clipboard hệ thống thực
  • Vì vậy, Clipboard Events API có thể xử lý kiểu tùy ý, nhưng tương tác với clipboard thực chỉ giới hạn trong handler copy/paste do user agent tạo ra

Ghi kiểu tùy chỉnh từ nút Copy

  • Nút Copy trong menu chuột phải của Google Docs ghi ba biểu diễn vào clipboard
    • text/plain
    • text/html
    • application/x-vnd.google-docs-document-slice-clip+wrapped
  • Biểu diễn thứ ba là một kiểu tùy chỉnh chứa dữ liệu JSON, không thể ghi chỉ bằng async Clipboard API
  • Khi nhấn nút Copy, Google Docs gọi document.execCommand("copy")
  • execCommand("copy") có thể tạo ra sự kiện copy đáng tin cậy theo chương trình, như thể người dùng đã thực hiện lệnh sao chép
  • Trong Safari, execCommand("copy") cần có vùng chọn đang hoạt động để phát sinh sự kiện copy
    • Có thể tạo vùng chọn bằng cách thêm một input không rỗng vào DOM, chọn nó, gọi execCommand("copy"), rồi xóa đi

Khác biệt trình duyệt·OS của nút Paste

  • Nút Paste của Google Docs yêu cầu cài extension trên macOS, nhưng lại hoạt động trên laptop Windows
  • Có thể dùng document.queryCommandSupported("paste") để kiểm tra hỗ trợ lệnh paste
    • Trên macOS, Chrome và Firefox trả về false, Safari trả về true
    • Trên Windows, Chrome và Edge trả về true, Firefox trả về false
  • Safari hiển thị prompt xác nhận thao tác paste để cho người dùng biết rõ website đang đọc clipboard
  • Chưa xác định được vì sao Chrome cho phép execCommand("paste") trên Windows nhưng không cho trên macOS
  • Google Docs không fallback sang async Clipboard API khi không dùng được execCommand("paste")
    • Async Clipboard API không đọc được biểu diễn application/x-vnd.google-[...]
    • Biểu diễn HTML có chứa ID nội bộ

Cơ chế copy·paste dựa trên HTML của Figma

  • Nút Copy của Figma ghi hai biểu diễn vào clipboard
    • text/plain
    • text/html
  • Biểu diễn HTML chứa hai thẻ span rỗng, lần lượt có thuộc tính data-metadata, data-buffer
  • data-metadata là chuỗi JSON được mã hóa base64; sau khi giải mã có thể thấy các giá trị như fileKey, pasteID, dataType
  • data-buffer dài khoảng 26.000 ký tự ngay cả khi chỉ sao chép một frame rỗng, và có vẻ tăng tuyến tính theo lượng nội dung đã sao chép
  • Khi giải mã base64 data-buffer, sẽ thu được dữ liệu nhị phân bắt đầu bằng fig-kiwi, tức Kiwi message format
    • Kiwi là định dạng do Evan Wallace, đồng sáng lập và cựu CTO của Figma, tạo ra
    • Nó được dùng để mã hóa tệp .fig
  • Có thể dùng .fig file parser do Evan Wallace công bố để chuyển data-buffer thành tệp .fig và kiểm tra
  • Figma tạo một tệp Figma nhỏ, mã hóa nó bằng base64, rồi đặt vào thuộc tính data-buffer của một span HTML rỗng để lưu vào clipboard

Vì sao dùng biểu diễn HTML

  • Windows, macOS và Linux cung cấp các định dạng OS khác nhau để ghi dữ liệu vào clipboard
    • Windows cung cấp CF_HTML cho HTML
    • macOS cung cấp NSPasteboard.PasteboardType.html
  • Văn bản thuần, HTML và ảnh PNG có thể được ánh xạ sang các định dạng chuẩn trên nhiều OS
  • Các kiểu tùy ý như application/foo-bar không khớp tốt với định dạng chung của clipboard OS
  • Trình duyệt không ghi các biểu diễn tùy chỉnh đó vào định dạng clipboard chung của OS, mà lưu chúng trong định dạng clipboard tùy chỉnh riêng của từng trình duyệt
    • Kết quả là kiểu tùy chỉnh có thể copy·paste giữa các tab trong cùng trình duyệt
    • Nhưng không thể copy·paste giữa các ứng dụng khác nhau
  • Khi dùng text/html, dữ liệu có thể được ánh xạ sang định dạng clipboard chung của OS, nên ứng dụng khác dễ đọc hơn
  • Figma dùng text/html để copy·paste phần tử giữa figma.com trong trình duyệt và ứng dụng Figma native

Cách mỗi trình duyệt lưu dữ liệu tùy chỉnh

  • Trên macOS, nếu ghi text/plain, text/html, application/json, foo bar baz trong sự kiện copy rồi kiểm tra bằng Pasteboard Viewer, có thể thấy mỗi trình duyệt lưu khác nhau
  • Chrome thêm bốn mục vào Pasteboard
    • public.html: biểu diễn HTML
    • public.utf8-plain-text: biểu diễn văn bản thuần
    • org.chromium.web-custom-data: biểu diễn tùy chỉnh
    • org.chromium.source-url: URL trang web nơi thao tác copy diễn ra
  • Firefox cũng tạo public.html, public.utf8-plain-text, nhưng ghi dữ liệu tùy chỉnh vào org.mozilla.custom-clipdata
    • Khác với Chrome, Firefox không lưu source URL
  • Safari cũng tạo public.html, public.utf8-plain-text, và ghi dữ liệu tùy chỉnh vào com.apple.WebKit.custom-pasteboard-data
    • Trong mục này, nó còn lưu cả danh sách biểu diễn đầy đủ gồm văn bản thuần, HTML và source URL
  • Safari chỉ cho phép copy·paste kiểu tùy chỉnh giữa các tab trình duyệt khi domain của source URL giống nhau
    • Trên Chrome và Firefox không thấy giới hạn này

Raw Clipboard Access và Web Custom Formats

  • Raw Clipboard Access là API được đề xuất năm 2019 nhằm cung cấp cho ứng dụng web quyền truy cập đọc·ghi thô vào clipboard OS native
  • Raw Clipboard Access giải quyết vấn đề ứng dụng web bị giới hạn ở một số ít định dạng, khiến Figma và Photopea khó tương tác với phần lớn định dạng ảnh
  • Đề xuất này không tiến thêm do lo ngại bảo mật như thực thi mã từ xa trong ứng dụng native
  • Web Custom Formats là đề xuất cho phép ghi kiểu tùy chỉnh trong async Clipboard API, và Chromium đã triển khai vào năm 2022
  • Web Custom Formats dùng tiền tố "web " trước kiểu MIME
    • Ví dụ: web application/json
    • Khi đọc cũng dùng read() của async Clipboard API và getType("web application/json")
  • Web Custom Formats ghi hai loại dữ liệu vào clipboard OS native
    • Ánh xạ giữa kiểu dữ liệu và tên mục clipboard
    • Mục clipboard ứng với từng kiểu dữ liệu
  • Trên macOS, ánh xạ được lưu trong org.w3.web-custom-format.map
    • Ví dụ: "application/json": "org.w3.web-custom-format.type-0"
  • Mục org.w3.web-custom-format.type-[index] chứa dữ liệu thô của Blob
  • Cách này ngăn ứng dụng web ghi trực tiếp dữ liệu thô vào bất kỳ định dạng clipboard OS nào chúng muốn, nhờ đó tránh được vấn đề bảo mật của Raw Clipboard Access
  • Đổi lại, mục tiêu không phải là tương tác ngay với ứng dụng native cũ mà không cần cập nhật
    • Ứng dụng native phải được cập nhật để đọc định dạng Web Custom Formats
  • Web Custom Formats đã dùng được trên các trình duyệt dựa trên Chromium từ năm 2022, nhưng các trình duyệt khác vẫn chưa triển khai

Tùy chọn unsanitized

  • Khi đọc clipboard bằng async Clipboard API, trình duyệt có thể làm sạch dữ liệu
    • Có thể xóa các thẻ script nguy hiểm trong HTML
    • Có thể mã hóa lại ảnh PNG để tránh tấn công zip bomb
  • Tùy chọn unsanitized của read() cho phép yêu cầu dữ liệu chưa qua làm sạch
  • Tùy chọn này hiện chỉ được hỗ trợ trong các trình duyệt dựa trên Chromium
    • Được thêm vào cuối năm 2023
    • Các trình duyệt khác có thể hỗ trợ trong tương lai, nhưng có phản hồi cho thấy Safari khó có khả năng hỗ trợ

Lựa chọn thực tế

  • Hiện vẫn chưa có cách ghi kiểu clipboard tùy chỉnh nào hoạt động tốt trên mọi trình duyệt
  • Cách nhúng chuỗi base64 vào biểu diễn HTML như Figma tuy thô nhưng có thể vượt qua nhiều giới hạn của Clipboard API để truyền dữ liệu tùy chỉnh qua clipboard
  • Web Custom Formats đưa ra hướng đi an toàn và thực tế hơn cho việc dùng kiểu tùy chỉnh, nhưng cần được triển khai rộng rãi trên các trình duyệt lớn

1 bình luận

 
GN⁺ 2024-09-02
Ý kiến trên Hacker News
  • Bài viết hay. Giờ thì tôi hiểu vì sao dán có/không kèm định dạng trong Google Docs trên Firefox của Mac hoạt động không ổn
    Điều thú vị là Google đang dùng một API đã bị loại bỏ để cố đưa định dạng nội dung riêng của họ vào clipboard

    • Có lẽ một ngày nào đó phải chính thức tuyên bố Google Web là một fork của web chính thức
  • Cách đáng tin cậy nhất để đưa dữ liệu ứng dụng tùy chỉnh vào clipboard có vẻ là nhúng dữ liệu vào HTML, giống như Figma
    Ưu điểm là khi ứng dụng nhận không hỗ trợ, bạn còn có thể định nghĩa cả hành vi thất bại bằng một thông điệp HTML

  • WordPress cũng đụng đến vấn đề này. Nếu cắt rồi dán nhiều đoạn văn trong chế độ trình soạn thảo, mọi thứ có thể hỏng nặng
    Có lẽ vì các đoạn văn thực ra nằm trong những vùng DIV khác nhau, dưới các logic điều khiển và hiệu ứng khác nhau
    Ngoài ra, máy còn tự nâng thứ tôi nghĩ là ASCII lên UTF-8 hoặc ISO Latin-1, rồi hành xử kiểu Clippy như “tôi đã đổi dấu ngoặc kép cho đẹp hơn, sau này nhớ cảm ơn nhé”, trong khi tôi chẳng hề muốn. Nếu tôi muốn `this' thì tôi đã không gõ 'this'

  • Hồi còn là sinh viên, JavaScript từng có thể đọc clipboard mà không cần người dùng đồng ý, và tôi đã làm một website tên là getpasted
    Đó là trang tự động dán nội dung clipboard rồi đưa lên cơ sở dữ liệu công khai, và tất nhiên cũng có người ghét nó
    Dù vậy, xét như một dự án để cho thấy việc có thể đọc clipboard bất cứ lúc nào là hoàn toàn có thật thì cũng ổn

    • Mọi người sẽ ngạc nhiên nếu biết rằng trên Windows 11, mặc định toàn bộ dữ liệu clipboard được gửi lên máy chủ của Microsoft thông qua Clipboard History / Cloud Clipboard
  • Sindre Sorhus, tác giả của Pasteboard Manager[0], cũng là người tạo ra thư viện shortcut Actions[1] và nhiều ứng dụng iPhone/Mac khác. Không rõ anh ấy có ở trên HN không
    0. https://apps.apple.com/us/app/pasteboard-viewer/id1499215709

    1. https://apps.apple.com/us/app/actions/id1586435171
  • Sự kết hợp giữa phạm vi và chiều sâu đặc biệt tốt. Bài viết đề cập cả khác biệt theo hệ thống/trình duyệt, đồng thời giải thích cả cạm bẫy và cách đi vòng

    • Tôi đã cố gắng giảm bớt chi tiết quá mức và các nhánh phụ trong bài. Bài khá dài, nhưng lần này có vẻ đã cân bằng được nên tôi mừng
  • Liên quan đến chuyện lấy dữ liệu “riêng tư” trong trình duyệt, webapp ngân hàng của tôi khi đăng nhập đã hiển thị hostname của tôi là aluminium và yêu cầu xác thực hai bước
    Tôi không biết họ biết bằng cách nào. Khi truy cập trên di động, nó còn có thể xem SMS chứa mã xác thực hai bước và tự động dán vào. Đó là môi trường Pixel+Chrome hoặc Linux+Chrome

    • Mã xác thực hai bước có lẽ rất có khả năng là tính năng của Chrome. Safari cũng hiển thị mã xác thực SMS dưới dạng gợi ý tự động điền, và Chrome trên Android chắc có thể tự nhập luôn
      Hostname thì khó hơn. Cần kiểm tra xem bạn có thực sự chưa từng cung cấp thông tin đó cho ngân hàng dưới dạng như tên người dùng hay không. Tôi cũng tò mò đó là ngân hàng nào
  • Bài này cho thấy rõ vì sao webapp không thể tốt như ứng dụng native
    Webapp luôn là mã “không đáng tin cậy”, nên quyền truy cập tài nguyên của máy cục bộ bị hạn chế một cách tùy ý và nhân tạo

    • Mặc định không tin tưởng là một tính năng. Trừ khi người dùng là chuyên gia bảo mật được huấn luyện cao và luôn cảnh giác, họ rất khó tự bảo vệ mình
      Giờ không còn là thời Internet sơ khai khi script kiddie hoành hành nữa, cũng không phải là không gian chỉ dành cho dân geek. Đây là thời đại mà các tổ chức liên hệ với chính phủ tấn công ransomware vào hạ tầng trọng yếu để tài trợ cho chương trình hạt nhân. Quyền truy cập tùy ý vào tài nguyên máy cục bộ chính là thứ khiến những việc như vậy khả thi
      Webapp trong các trình duyệt hiện đại tự nhiên nằm trong sandbox mạnh hơn, nhưng trên các hệ điều hành hiện đại, ứng dụng native cũng bị xem là đối tượng không đáng tin. Khi chạy một ứng dụng mới, hộp thoại xác nhận sẽ xuất hiện trước khi nó truy cập ra ngoài thư mục dữ liệu ứng dụng đã được cách ly
  • Nhưng tôi tò mò tiện ích mở rộng Chrome nào đã làm hiện cảnh báo trên MacBook