RFC-0179:基本剪貼簿服務

RFC-0179:基本剪貼簿服務
狀態已接受
領域
  • HCI
說明

基本剪貼簿服務的提案,讓使用者無論執行元件為何,都能在元件之間安全地複製及貼上文字內容。

問題
毛皮變化
作者
審查人員
提交日期 (年-月-日)2022-05-16
審查日期 (年-月-日)2020-07-18

摘要

這個 RFC 導入了兩個由架構提供的全新通訊協定 fuchsia.ui.clipboard.Writerfuchsia.ui.clipboard.Reader,以及服務 以實作這些程式碼,提供使用者執行複製與貼上作業 以及對文字內容進行的作業

提振精神

許多面向使用者的現代化作業系統都提供圖形殼層 剪貼簿功能 (請參閱前圖片), 讓使用者以互動方式將資料複製到系統提供的記憶體緩衝區 稍後再將這些資料貼到其他位置

Fuchsia 過去採取基本剪貼簿通訊協定 這個程式碼已於 2019 年移除

在本 RFC 中,我們提議導入全新的剪貼簿通訊協定和實作方式 可以選擇整合 Fuchsia 產品。最迫切 就是需要複製及貼上 Unicode 文字的能力,因此這是 第一個疊代作業

許多現有作業系統的剪貼簿設施 原本在設計時,沒有安全性規定 允許任何程序隨時觀察到和/或修改剪貼簿,而不需 使用者的認知或意圖我們設計 Fuchsia 時,將安全性納入考量,包括:

  • 根據以下指示保護剪貼簿存取權 最低權限原則
  • 嘗試限制剪貼簿存取權,因此需要在 前景視窗 (請參閱 Fuchsia 景觀術語中的「檢視」)
  • 只有在不得已的情況下,才允許存取背景剪貼簿

相關人員

輔導員

davemoore@google.com

審查人員

Fuchsia HCI:neelsa@google.com、quiche@google.com

安全性: Palmer@google.com

隱私權:enoharemaien@google.com

Chromium:wez@google.com

Flutter:jmccandless@google.com

諮詢

azaslavsky、carolineliu@google.com、chaopeng@google.com、cpu@google.com ddorwin@google.com、fmil@google.com、jsankey@google.com、tjdetwiler@google.com

社交

  • 討論 Fuchsia Input Team 文件審查主題
  • 在 Fuchsia 安全諮詢時間討論

設計

權限等級

在圖形殼層環境中存取剪貼簿的範圍 分為三個層級

  1. Shell 中介、專注於焦點
    元件只有在回應明確要求時,才能存取剪貼簿 使用者動作;且只有在 目前都有輸入焦點
  2. 聚焦於
    如果元件具備輸入焦點,就能隨時存取剪貼簿。
  3. 未限制
    元件隨時可以存取剪貼簿。

在這個 RFC 中,我們只涵蓋 (2) 對焦相依的範圍。

此目標並未規劃範圍 (1) 和 (3) 的實作方式 時間;就需要其他 RFC。

用途

對於初始 RFC,我們會考慮幾個簡單但常見的使用案例:

  • 在網路瀏覽器中,將網頁內文的網址複製到網址 列
  • 將殼層指令從網路瀏覽器複製到終端機
  • 將網路瀏覽器中的資訊複製到工作站產品的 意見回饋對話方塊 (在 Flutter 中實作)

通訊協定和服務

我們推出了兩個可偵測的新 FIDL 通訊協定 「fuchsia.ui.clipboard.FocusedReaderRegistry」和 fuchsia.ui.clipboard.FocusedWriterRegistry (在合作夥伴 SDK 中)。這些 系統將透過新的元件 clipboard.cm 來實作及公開通訊協定。 並在工作階段運作領域中執行元件會包含在工作站中 產品,可用於其他需要此產品的 Fuchsia 產品。

獲得 FocusedWriterRegistry 和 「FocusedReaderRegistry」功能將可要求 fuchsia.ui.clipboard.Writerfuchsia.ui.clipboard.Reader。 並「可能」隨時要求取得這些連線 (假設其具備有效連結) ViewRef),但如果系統傳回錯誤,則 WriterReader 的方法會傳回錯誤 用戶端的檢視畫面沒有輸入焦點。

library fuchsia.ui.clipboard;

/// A protocol that allows graphical clients that own
/// [`ViewRef`s](https://cs.opensource.google/fuchsia/fuchsia/+/main:/src/development/graphics/scenic/concepts/view_ref) to request read ("paste")
/// access to the clipboard. Clients can register for access at any time, but `GetItem` calls will
/// only succeed while the view has input focus.
@discoverable
protocol FocusedReaderRegistry {
    /// If the `ViewRef` is valid, the clipboard server will allow the client to send commands using
    /// the given `Reader`. If the `ViewRef` later becomes invalid, the `Reader`'s channel will be
    /// closed.
    RequestReader(resource table {
        1: view_ref fuchsia.ui.views.ViewRef;
        2: reader_request server_end:Reader;
    }) -> (table {}) error ClipboardError;
};

/// A protocol that allows graphical clients that own `ViewRef`s to request write ("copy") access to
/// the clipboard. Clients can register for access at any time, but `SetItem` calls will only
/// succeed while the view has input focus.
@discoverable
protocol FocusedWriterRegistry {
    /// If the `ViewRef` is valid, the clipboard server will allow the client to send commands using
    /// the given `Writer`. If the `ViewRef` later becomes invalid, the `Writer`'s channel will be
    /// closed.
    RequestWriter(resource table {
        1: view_ref fuchsia.ui.views.ViewRef;
        2: writer_request server_end:Writer;
    }) -> (table {}) error ClipboardError;
};

/// Allows data to be read from the clipboard, i.e. pasted.
protocol Reader {
    /// Reads a single item from the clipboard. If the client's `View` does not have input focus, an
    /// error will be returned. If there is no item on the clipboard, `ClipboardError.EMPTY` will
    /// be returned.
    GetItem(table {}) -> (ClipboardItem) error ClipboardError;
};

/// Allows data to be written to the clipboard, i.e. copied.
protocol Writer {
    /// Writes a single item to the clipboard. If the client's `View` does not have input focus, an
    /// error will be returned.
    SetItem(ClipboardItem) -> (table {}) error ClipboardError;

    /// Clears the contents of the clipboard. If the client's `View` does not have input focus, an
    /// error will be returned.
    Clear(table {}) -> (table {}) error ClipboardError;
};

/// Set of errors that can be returned by the clipboard server.
type ClipboardError = flexible enum {
    /// An internal error occurred. All the client can do is try again later.
    INTERNAL = 1;

    /// The clipboard was empty, or the requested item(s) were not present on the clipboard.
    EMPTY = 2;

    /// The client sent an invalid request, e.g. missing requiring fields.
    INVALID_REQUEST = 3;

    /// The client sent the server an invalid `ViewRef` or a `ViewRef` that is already associated
    /// with another client.
    INVALID_VIEW_REF = 4;

    /// The client attempted to perform an operation that requires input focus, at a moment when
    /// it did not have input focus. The client should wait until it has focus again before
    /// retrying.
    UNAUTHORIZED = 5;
};

在初始版本中,剪貼簿僅支援複製及貼上 最大 32 KB 的 UTF-8 字串。用戶端可能會指定 MIME 類型 資料;預設值為 "text/plain;charset=UTF-8"

後續的修訂版本將新增對 VMO 的支援,以啟用 可以複製及貼上任意資料

/// The maximum length of a plain-text clipboard item in bytes. Although FIDL messages support
/// larger messages, this limit allows space to be reserved for potential other fields in the
/// message. Larger payloads will be supported by VMOs in `ClipboardItemData` in future revisions.
const MAX_TEXT_LENGTH uint32 = 32768;

/// The maximum length of a MIME Type identifier. Per
/// [IETF RFC 4288](https://datatracker.ietf.org/doc/html/rfc4288#section-4.2), a MIME type may have
/// up to 127 characters before and 127 characters after the slash, for a total of 255.
const MAX_MIME_TYPE_LENGTH uint32 = 255;

/// A single item on the clipboard, consisting of a MIME type hint and a payload.
type ClipboardItem = resource table {
    /// MIME type of the data, according to the client that placed the data on the clipboard.
    /// *Note:* The clipboard service does not validate clipboard items and does not guarantee that
    /// they conform to the given MIME type's specifications.
    1: mime_type_hint string:MAX_MIME_TYPE_LENGTH;
    /// The payload of the clipboard item.
    2: payload ClipboardItemData;
};

/// The payload of a `ClipboardItem`. Future expansions will support additional transport formats.
type ClipboardItemData = flexible resource union {
    /// A UTF-8 string.
    1: text string:MAX_TEXT_LENGTH;
};

實作

這會在幾個階段發生:

  1. 如上所述,為新的 fuchsia.ui.clipboard FIDL 程式庫提交 API 審查。
  2. 實作在工作階段運作領域中執行的新剪貼簿伺服器元件 會公開 fuchsia.ui.clipboard.FocusedWriterRegistryfuchsia.ui.clipboard.FocusedReaderRegistry 通訊協定。
  3. 可透過簡單的元件,展現與新通訊協定的整合 會管理 View 檢視畫面
  4. 將新通訊協定的支援功能整合至 Chromium 和 Flutter 跑者

成效

新增服務會讓二進位檔耗用額外的儲存空間,以及 用於二進位和剪貼簿內容的記憶體註冊 剪貼簿存取權會使用開啟的 Zircon 管道來耗用資源。

安全性考量

你必須接受安全性審查

跨元件通訊

隨著剪貼簿服務問世,構成一個新的跨元件 通訊管道。這樣就能為元件 蓄意或無意間利用彼此的漏洞。

不受信任的內容

剪貼簿服務不保證 ClipboardItem 資料或 MIME 類型提示。因此客戶不應信任 ,並應確認資料是否適合其使用 確認是否屬於此情況

具體而言,客戶應執行任何剖析、解讀或轉換, 具備複雜格式,具備較低的「沙箱」權限並在 比 C/C++ 更安全(請參閱 規則 2 )。

如果是 ClipboardItemData.text 變數,系統會自動進行 UTF-8 驗證 由每個用戶端 (以及剪貼簿) 使用的 FIDL 程式庫執行 服務)。

不過,即使使用純正、有效的 UTF-8 文字,單一元件也能 透過剪貼簿傳送任意文字給他人,讓更多樣的門口出現。 入侵向量,包含:

  • 文字小工具中的溢位錯誤
  • 文字轉譯堆疊中的錯誤
  • 同儕攻擊 (誘導使用者使用外觀相異的字符 字元,例如蓄意將使用者導向網路釣魚網域)
  • 應用程式專屬文字剖析錯誤
  • 將非預期的程式碼貼到指令提示中

在這些情況下,多數 - 應用程式的 顯示任何第三方或使用者提供的內容,但剪貼簿張貼了 額外挑戰惡意應用程式可以回應有效的使用者 複製指令,將非預期的資料 (未顯選) 放入 假冒他人身分 混淆代理 貼上。

未經授權的存取

上圖所述,元件可能需要讀取或讀取 或是在使用者不知情的情況下寫入剪貼簿。

這可減輕以下影響:

  • 可用於授予或拒絕複製及貼上存取權的通訊協定 讓資源精細
  • fuchsia.ui.clipboard.Focused* 通訊協定中,滿足以下條件: 剪貼簿存取權只會授予含有輸入焦點的前景檢視畫面

在剪貼簿 API 日後擴充時,我們可能會提供 系統殼層可以用來觀察剪貼簿 API 事件的通訊協定 使用者存取剪貼簿時,一律顯示視覺化通知。

日後只要加入不信任的元件和新的剪貼簿使用方式 案例,我們就必須重新考慮是否該允許未經授權的讀取行為 會在背景中傳回空白的剪貼簿項目,而不是 ClipboardError.UNAUTHORIZED。 以減少剪貼簿存取的相關資訊。

ViewRef」和「焦點」驗證

剪貼簿服務必須仰賴 View 的 聚焦鏈系統 判斷目前聚焦的檢視畫面,因此有權 存取剪貼簿。因此,剪貼簿的判斷結果 對視覺焦點只與 Sight 對輸入焦點的判斷, 一些瑕疵:

  • ViewRefs, 組成一個焦點鏈,以便輕鬆複製某個元件並傳送至 另一個例子。透過此機制,惡意元件可以合作 這種身分會相互冒用,藉此呈現輸入焦點。(雖然 至少要取得 ViewRef 的原始擁有者信任 副本 ViewRef 的收件者)。
  • 聚焦變更的內容 競爭狀況

安全性審查結果

  • 這個 MVP API 十分有限,因此能限制遭受攻擊的途徑。
  • 我們仰賴基礎 FIDL 反序列化程序來正確驗證 UTF-8 字串。這是攻擊行為 但因為服務字串 反序列化仰賴 Rust 的 std::str::String 實作, 在 Fuchsia 和更廣泛的 Rust 環境中,對記憶體安全進行大量測試 生態系統
  • 我們認為「ViewRef」解決方案是追蹤觀看次數的理想基礎 「焦點和使用者意圖」等

隱私權注意事項

必須接受隱私權審查。

未經授權貼上

如果未經授權存取剪貼簿的內容,會有隱私權風險。 讓惡意元件得以取得使用者的任何私人資料 。如所述, fuchsia.ui.clipboard.Focused* 個通訊協定會要求檢視表,藉此降低這個風險 至少具有輸入焦點 (並在前景顯示),才能 存取剪貼簿。然而,這意味著應用程式可以擷取 即使立即聚焦於剪貼簿, 這並不是使用者的意圖在過去的「系統殼層」中 每當元件讀取 剪貼簿。

側管道攻擊

於日後疊代剪貼簿服務時,再新增任意值 包括資料類型和長度 記憶體分析結果或許會顯示 資訊 (例如剪貼簿緩衝區的大小) 以提示其內容。

剪貼簿內容持續性

這個階段僅支援複製短字串和剪貼簿內容 是儲存在記憶體中,而不是儲存在磁碟中。

我們不會記錄或公開剪貼簿的內容 「檢查」

跨安全性環境存取

Fuchsia 產品可在不同的安全性環境中執行 UI 元素。 例如:或在預先驗證情境中,使用這組 ID紫紅色 必須「必須」禁止在不同安全性環境中共用剪貼簿內容 界定範圍例如,使用者在登入後複製了密碼,之後卻複製了密碼 鎖定螢幕,使用者無法將密碼貼到螢幕鎖定中 畫面對話方塊。

您可以執行個別的剪貼簿執行個體,藉此達成這個區隔。 服務。

測試

這項功能將會透過單元和整合測試進行測試:

  • 剪貼簿服務中的單元測試
  • 整體剪貼簿服務的整合測試
  • 整合測試剪貼簿 (Sight) 服務 以及 Flutter 或 Chromium 執行器

說明文件

fuchsia.ui.clipboard API 會連同 fidldoc 記錄

我們會以獲得良好註解的簡單元件來說明本通訊協定的使用方式 請參閱導入的相關說明。

缺點、替代方案和未知

想要提供整個系統通用的剪貼簿服務,目前沒有可行的替代方案。 面向使用者的作業系統執行者無法提供這項功能 這是因為他們無法在 不同的執行階段

在本文所述的設計選項中,替代做法可能是 從限制更嚴格的「由殼層中介服務、聚焦於焦點」開始剪貼簿 或完全無限制的通訊協定 (詳情請參閱 存取層級)。

採用殼層中介服務的方法雖然安全性較高,但可能過於嚴格,以免無法 很多用途都很可行舉例來說

  • 防止應用程式在內容選單中提供複製及貼上指令
  • 幹擾 Chromium 網路剪貼簿 API 的功能 跑者

無限制的方法,對某些小眾應用而言很實用, 無法預設提供太多隱私權風險

我們會先根據輸入焦點建立中間的存取層級 能夠:

  • 優先執行剪貼簿服務中的某些安全性和隱私權保證 從一開始
  • 鼓勵執行者的最小特權原則整合 Fuchsia 剪貼簿
  • 避免限制過度對實際整合 現有跑者

日後的工作

  • 提供用來觀察剪貼簿 API 事件 (讀取和寫入) 的通訊協定 系統殼層在執行以下動作時, 已存取剪貼簿。

  • 展開支援的資料格式和酬載大小組合,尤其是 透過傳送端用戶端擁有的 VMO

既有藝術品和參考資料

紫紅色

Fuchsia 先前有個 最簡單剪貼簿 API 可做為 Modular Framework 代理程式 (即模組架構代理程式) 中導入 fuchsia.modular.Clipboard 能力可儲存或擷取 UTF-8 字串。 (這項功能已於 2019 年 11 月清除)。

Linux:X11

X11 提供多種稱為「選擇」的內容儲存區域是哪個 常見的是 CLIPBOARDPRIMARY (隱式文字選取剪貼簿)。

傳送應用程式向 X 伺服器宣告其「擁有」下列其中一項 特定資料格式的選項 (XSetSelectionOwner())。接著,會等待後續事件。

接收應用程式會在其中一個視窗要求選擇 並轉換成支援的特定格式 (XConvertSelection())。

X 伺服器會將要求轉送至傳送端應用程式,如果應用程式傳送要求, 支援所要求的格式,並透過 X 伺服器將資料傳送至 接收應用程式。如果內容較大,就必須分段 可包含最多 256 KB 的片段

如果來源視窗遭到刪除,選取範圍就會遺失,實際上 (1) 大多數應用程式會將選取的選項保留在使用者隱形的視窗中 此應用程式同樣不會關閉,且 (2) 常見的 Linux 發行版會包含剪貼簿管理工具 取得所選項目的擁有權,但即使該內容的原始著作權擁有者也一樣 就會結束應用程式

詳情請參閱 https://www.uninformativ.de/blog/postings/2017-04-02/0/POSTING-en.html.

Linux:Wayland

傳送應用程式必須聚焦,並通知合成器 具有 wl_data_source,表示資料來源支援的 MIME 類型。 並註冊事件接聽程式。然後會等待 send 事件。

接收應用程式,在嘗試要嘗試以下行為時,必須依序聚焦在 貼上,監聽資料 offer 事件,以判斷剪貼簿是否已 。需要貼上內容時,程式碼會呼叫 wl_data_offer_receive 並傳入 要求的 MIME 類型和檔案描述元 (通常是管道的寫入結尾)。

傳送應用程式收到 send 事件,並寫入指定檔案 描述元;接收端應用程式讀取其端。

詳情請參閱 https://emersion.fr/blog/2020/wayland-clipboard-drag-and-drop/.

Windows (win32)

系統會呼叫 OpenClipboard() 並傳入 目前視窗的控點傳送應用程式會藉由下列方法清除現有資料: 呼叫 EmptyClipboard(),然後呼叫 SetClipboardData(),傳入 整數資料類型 ID 和資料本身傳送資料的記憶體 必須由使用 GlobalAlloc() 進行分配。

有多種標準剪貼簿資料類型:或者,您也可以 呼叫 RegisterClipboardFormat() 以取得自訂全域格式 ( 直到重新啟動為止),或使用特定範圍內的 ID 來表示 私人剪貼簿格式。如果是非私人格式,OS 會取得 傳入且會負責其最終刪除物件的物件; 如果是私人格式,原始視窗會負責清理 就會被銷毀。如果是延遲格式轉換,來源回溯期 可以將 NULL 資料值傳遞至 SetClipboardData(),之後再傳遞 WM_RENDERFORMAT,請算繪要求的格式,並將預留位置替換為 對 SetClipboardData() 發出的另一個呼叫。我們建議開發人員設定剪貼簿 盡量擷取不同格式的資料

接收應用程式也會擷取全域剪貼簿的控制代碼, 視窗,檢查可用格式清單 (包括明確支援的格式) 傳送的應用程式以及提供自動轉換功能的應用程式 OS) 會呼叫 GetClipboardData(),取得剪貼簿物件的控制代碼 ,並使用 GlobalLock() 鎖定該全域資源 並存取當中的內容

我們也提供方法讓 Windows 註冊,以監控對 複製的內容

詳情請參閱 https://docs.microsoft.com/zh-tw/windows/win32/dataxchg/using-the-clipboard 和 https://docs.microsoft.com/en-us/windows/win32/dataxchg/clipboard-operations.

Android

傳送的應用程式會建立 ClipData 物件,其中包含支援的清單 MIME 類型,並在 ClipData 中填入一或多個項目,例如 字串,指向任何資料或 Intent (適用於應用程式) 捷徑)。接著,傳送端應用程式會取得對 ClipboardManager 物件並將 ClipData 物件傳遞至 setPrimaryClip()

如果複製內容 URI,傳送端應用程式就必須匯出一個 ContentProvider 可提供該 URI 的資料。

接收應用程式會取得全域 ClipboardManager 的參照。 檢查是否有主要短片,然後檢查它是否支援 任何 ClipData.Item。如果貼上純字串,接收端 只要呼叫 getText() 即可。如果要貼上內容 URI 接收應用程式必須建立 ContentResolver 例項,query()該例項 使用指定的 URI,然後從傳回的 Cursor 擷取資料。

自 Android 12 起,作業系統會在單一應用程式存取時顯示浮動式訊息 ClipData

詳情請參閱 https://developer.android.com/guide/topics/text/copy-paste.

MacOS

系統通盤「貼上板」可透過 NSPasteboard.general 存取 ] 欄位。

傳送應用程式會藉由傳入方法 writeObjects() 來複製項目 實作 NSPasteboardWriting 通訊協定的物件陣列。 實作項目包括字串和其他常見資料類型 NSPasteboardItem,用於放送自訂資料類型的包裝函式。 NSPasteboardWriting 會提供支援的統一類型 ID 清單 (UTI,相當於 Apple 的 MIME 類型),以及是否可取得資料 或「遭駭」相對地,NSPasteboardItem 可以直接換行 或資料供應商

在接收端上,應用程式可查詢一般 NSPasteboard, 這些可讀取的類型,包括 篩選服務使用者可以選擇閱讀全部或部分項目 儲存的圖片

詳情請參閱 ​​https://developer.apple.com/documentation/appkit/nspasteboard.

iOS

iOS 剪貼簿 API 與 MacOS 的 API 十分類似。系統通用的貼上板是 透過 UIPasteboard.general 存取。

傳送時,你可以透過多種方式新增一或多個項目; 加上 UTI 類型標籤您也可以將 NSItemProviders,這會延遲提供值。為了方便起見 標準資料類型有專屬的可讀取/寫入陣列屬性 UIPasteboard 執行個體:stringsimagesurlscolors 並以個別版本的形式處理,只提供前 以及每種類型

在接收端上,可以透過索引或依據索引,擷取任何所選項目 類型。

自 iOS 14 起,系統擷取另一端安裝的貼上板內容 應用程式觸發了系統通知減少誤導通知 再實際貼上,iOS 可讓客戶查詢 看板 (hasStringshasImages) 上有資料類型,沒有 存取資料

詳情請參閱 https://developer.apple.com/documentation/uikit/uipasteboard.

網路 API

雖然網頁上的剪貼簿互動主要是由網路處理 但也會有 JavaScript API 讓網頁與剪貼簿互動,而不需要 就必須直接使用者指令

舊版 ClipboardEvent API 允許指令碼監聽 "cut""copy"、 或 DOM Element 上的 "paste" 事件,然後存取事件的 clipboardData 欄位,允許透過 MIME 呼叫 setDatagetData 類型。您也可透過程式輔助方式叫用 "cut""copy""paste" (位於目前聚焦的元素)。基於隱私權考量 在 "cut""copy" 上,您無法再使用程式輔助貼上功能 事件時,無法讀取剪貼簿內容。

全新的非同步 Clipboard API 現已可供使用,並由網站使用者守護 授予其要求的權限。如果使用者授予權限,指令碼就能存取 navigator.clipboard,然後依序為writeText()readText()write() ClipboardItem,包含一或多個由 MIME 類型鍵入的 blob。(非圖片) 部分瀏覽器仍在實驗階段 MIME 類型)。

詳情請參閱 https://whatwebcando.today/clipboard.html 和 https://developer.mozilla.org/en-US/docs/Web/API/Clipboard.

ChromeOS

Chrome 擴充功能可以使用上述剪貼簿 API,前提是必須遵守 授予其要求的權限。