安全剪貼簿處理
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
OWASP 類別:MASVS-CODE:程式碼品質
總覽
Android 提供強大的架構,稱為剪貼簿,可在應用程式之間複製及貼上資料。如果這項功能導入方式不正確,可能會將使用者相關資料洩漏給未經授權的惡意人士或應用程式。
與剪貼簿資料外洩相關的具體風險取決於應用程式的性質,以及該應用程式處理的個人識別資訊 (PII)。對於金融應用程式來說,影響特別嚴重,因為這類應用程式可能會洩漏付款資料,或處理雙重驗證 (2FA) 碼。
可用來竊取剪貼簿資料的攻擊媒介會因 Android 版本而異:
- 舊版 Android (低於 Android 10,API 級別 29) 允許背景應用程式存取前景應用程式的剪貼簿資訊,因此惡意人士可能會直接存取任何複製的資料。
- 從 Android 12 (API 級別 31) 起,每當應用程式存取剪貼簿中的資料並貼上時,系統就會向使用者顯示 Toast 訊息,讓攻擊行為更難以隱匿。此外,為了保護個人識別資訊,Android 支援
ClipDescription.EXTRA_IS_SENSITIVE
或 android.content.extra.IS_SENSITIVE
特殊標記。這可讓開發人員在鍵盤 GUI 中以視覺效果模糊處理剪貼簿內容預覽畫面,避免複製的資料以純文字形式顯示,進而遭到惡意應用程式竊取。事實上,如果未實作上述其中一個標記,攻擊者可能會透過肩並走動、或在背景執行的惡意應用程式,擷取合法使用者活動的螢幕截圖或錄製影片,從而將複製到剪貼簿的機密資料外洩。
影響
不當的剪貼簿處理作業可能會導致使用者相關的機密或財務資料遭到惡意人士竊取。這可能有助於攻擊者進一步採取行動,例如網路釣魚活動或身分盜用。
因應措施
標示機密資料
這項解決方案可在鍵盤 GUI 中,將剪貼簿內容預覽畫面以視覺效果模糊處理。呼叫 ClipboardManager.setPrimaryClip()
前,請先使用 ClipDescription.EXTRA_IS_SENSITIVE
或 android.content.extra.IS_SENSITIVE
標記任何可複製的機密資料,例如密碼或信用卡資料。
Kotlin
// If your app is compiled with the API level 33 SDK or higher.
clipData.apply {
description.extras = PersistableBundle().apply {
putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true)
}
}
// If your app is compiled with API level 32 SDK or lower.
clipData.apply {
description.extras = PersistableBundle().apply {
putBoolean("android.content.extra.IS_SENSITIVE", true)
}
}
Java
// If your app is compiled with the API level 33 SDK or higher.
PersistableBundle extras = new PersistableBundle();
extras.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
clipData.getDescription().setExtras(extras);
// If your app is compiled with API level 32 SDK or lower.
PersistableBundle extras = new PersistableBundle();
extras.putBoolean("android.content.extra.IS_SENSITIVE", true);
clipData.getDescription().setExtras(extras);
強制要求使用最新 Android 版本
強制應用程式在 Android 10 (API 29) 以上版本執行,可防止背景程序存取前景應用程式中的剪貼簿資料。
如要強制應用程式僅在 Android 10 (API 29) 以上版本上執行,請在 Android Studio 中,針對專案中的 Gradle 建構檔案設定以下版本設定值。
Groovy
android {
namespace 'com.example.testapp'
compileSdk [SDK_LATEST_VERSION]
defaultConfig {
applicationId "com.example.testapp"
minSdk 29
targetSdk [SDK_LATEST_VERSION]
versionCode 1
versionName "1.0"
...
}
...
}
...
Kotlin
android {
namespace = "com.example.testapp"
compileSdk = [SDK_LATEST_VERSION]
defaultConfig {
applicationId = "com.example.testapp"
minSdk = 29
targetSdk = [SDK_LATEST_VERSION]
versionCode = 1
versionName = "1.0"
...
}
...
}
...
在指定時間後刪除剪貼簿內容
如果應用程式要在 Android 10 (API 級別 29) 以下版本上執行,則任何背景應用程式都能存取剪貼簿資料。為了降低這類風險,建議您實作函式,在特定時間過後清除複製到剪貼簿的所有資料。這項功能會從 Android 13 (API 級別 33) 開始自動執行。針對較舊的 Android 版本,您可以在應用程式程式碼中加入下列程式碼片段,即可執行這項刪除作業。
Kotlin
//The Executor makes this task Asynchronous so that the UI continues being responsive
backgroundExecutor.schedule({
//Creates a clip object with the content of the Clipboard
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = clipboard.primaryClip
//If SDK version is higher or equal to 28, it deletes Clipboard data with clearPrimaryClip()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
clipboard.clearPrimaryClip()
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
//If SDK version is lower than 28, it will replace Clipboard content with an empty value
val newEmptyClip = ClipData.newPlainText("EmptyClipContent", "")
clipboard.setPrimaryClip(newEmptyClip)
}
//The delay after which the Clipboard is cleared, measured in seconds
}, 5, TimeUnit.SECONDS)
Java
//The Executor makes this task Asynchronous so that the UI continues being responsive
ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor();
backgroundExecutor.schedule(new Runnable() {
@Override
public void run() {
//Creates a clip object with the content of the Clipboard
ClipboardManager clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = clipboard.getPrimaryClip();
//If SDK version is higher or equal to 28, it deletes Clipboard data with clearPrimaryClip()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
clipboard.clearPrimaryClip();
//If SDK version is lower than 28, it will replace Clipboard content with an empty value
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
ClipData newEmptyClip = ClipData.newPlainText("EmptyClipContent", "");
clipboard.setPrimaryClip(newEmptyClip);
}
//The delay after which the Clipboard is cleared, measured in seconds
}, 5, TimeUnit.SECONDS);
資源
這個頁面中的內容和程式碼範例均受《內容授權》中的授權所規範。Java 與 OpenJDK 是 Oracle 和/或其關係企業的商標或註冊商標。
上次更新時間:2025-07-26 (世界標準時間)。
[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["缺少我需要的資訊","missingTheInformationINeed","thumb-down"],["過於複雜/步驟過多","tooComplicatedTooManySteps","thumb-down"],["過時","outOfDate","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["示例/程式碼問題","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間:2025-07-26 (世界標準時間)。"],[],[],null,["# Secure Clipboard Handling\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-CODE: Code Quality](https://mas.owasp.org/MASVS/10-MASVS-CODE)\n\nOverview\n--------\n\nAndroid offers a powerful framework referred to as the [clipboard](/develop/ui/views/touch-and-input/copy-paste#Clipboard) for\ncopying and pasting data between applications. An improper implementation of\nthis feature could expose user-related data to unauthorized malicious actors or\napplications.\n\nThe specific risk associated with the exposure of clipboard data depends on the\nnature of the application and the Personal Identifiable Information (PII) it is\nhandling. The impact is especially high for financial applications, as they may\nexpose payment data, or apps that handle two-factor-authentication (2FA) codes.\n\nThe attack vectors that could be leveraged in order to exfiltrate clipboard data\nvary depending on Android version:\n\n- [Android versions older than Android 10 (API level 29)](/about/versions/10/privacy/changes#clipboard-data) allow background applications to access foreground app clipboard information, potentially allowing direct access to any copied data by malicious actors.\n- From Android 12 onwards (API level 31), every time an application accesses data within the clipboard and pastes it, a toast message is shown to the user, making it more difficult for attacks to go unnoticed. Additionally, in order to protect PII, Android supports the `ClipDescription.EXTRA_IS_SENSITIVE` or `android.content.extra.IS_SENSITIVE` special flag. This allows developers to visually obfuscate the clipboard content preview within the keyboard GUI, preventing copied data from being visually shown in clear-text and potentially stolen by malicious applications. Not implementing one of the aforementioned flags could in fact allow attackers to exfiltrate sensitive data copied to the clipboard by either shoulder surfing or through malicious applications that, while running in background, take screenshots or record videos of a legitimate user's activities.\n\nImpact\n------\n\nThe exploitation of improper clipboard handling could result in user-related\nsensitive or financial data being exfiltrated by malicious actors. This may aid\nattackers in conducting further actions such as phishing campaigns or identity\ntheft.\n\nMitigations\n-----------\n\n### Flag Sensitive Data\n\nThis solution is employed to visually obfuscate the clipboard content preview\nwithin the keyboard GUI. Any sensitive data that can be copied, such as\npasswords or credit card data, should be flagged with\n`ClipDescription.EXTRA_IS_SENSITIVE` or `android.content.extra.IS_SENSITIVE`\nbefore calling [`ClipboardManager.setPrimaryClip()`](/reference/android/content/ClipboardManager#setPrimaryClip(android.content.ClipData)). \n\n### Kotlin\n\n // If your app is compiled with the API level 33 SDK or higher.\n clipData.apply {\n description.extras = PersistableBundle().apply {\n putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true)\n }\n }\n\n // If your app is compiled with API level 32 SDK or lower.\n clipData.apply {\n description.extras = PersistableBundle().apply {\n putBoolean(\"android.content.extra.IS_SENSITIVE\", true)\n }\n }\n\n### Java\n\n // If your app is compiled with the API level 33 SDK or higher.\n PersistableBundle extras = new PersistableBundle();\n extras.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);\n clipData.getDescription().setExtras(extras);\n\n // If your app is compiled with API level 32 SDK or lower.\n PersistableBundle extras = new PersistableBundle();\n extras.putBoolean(\"android.content.extra.IS_SENSITIVE\", true);\n clipData.getDescription().setExtras(extras);\n\n### Enforce Latest Android Versions\n\nEnforcing the app to run on Android versions later or equal to Android 10 (API\n29) prevents background processes from accessing clipboard data in the\nforeground application.\n\nTo enforce the app to run only on Android 10 (API 29) or later, set the\nfollowing values for the version settings in the Gradle build files within your\nproject in Android Studio. \n\n### Groovy\n\n android {\n namespace 'com.example.testapp'\n compileSdk [SDK_LATEST_VERSION]\n\n defaultConfig {\n applicationId \"com.example.testapp\"\n minSdk 29\n targetSdk [SDK_LATEST_VERSION]\n versionCode 1\n versionName \"1.0\"\n ...\n }\n ...\n }\n ...\n\n### Kotlin\n\n android {\n namespace = \"com.example.testapp\"\n compileSdk = [SDK_LATEST_VERSION]\n\n defaultConfig {\n applicationId = \"com.example.testapp\"\n minSdk = 29\n targetSdk = [SDK_LATEST_VERSION]\n versionCode = 1\n versionName = \"1.0\"\n ...\n }\n ...\n }\n ...\n\n### Delete Clipboard content after a defined period of time\n\nIf the application is meant to run on Android versions lower than Android 10\n(API level 29), any background application can access clipboard data.\nIn order\nto reduce this risk, it's useful to implement a function that clears any data\ncopied to the clipboard after a specific period of time. This function is\n[automatically performed starting with Android 13 (API level 33)](https://blog.google/products/android/android-13/).\nFor older\nAndroid versions, this deletion can be performed by including the following\nsnippet within the application's code. \n\n### Kotlin\n\n //The Executor makes this task Asynchronous so that the UI continues being responsive\n backgroundExecutor.schedule({\n //Creates a clip object with the content of the Clipboard\n val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager\n val clip = clipboard.primaryClip\n //If SDK version is higher or equal to 28, it deletes Clipboard data with clearPrimaryClip()\n if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.P) {\n clipboard.clearPrimaryClip()\n } else if (Build.VERSION.SDK_INT \u003c Build.VERSION_CODES.P) {\n //If SDK version is lower than 28, it will replace Clipboard content with an empty value\n val newEmptyClip = ClipData.newPlainText(\"EmptyClipContent\", \"\")\n clipboard.setPrimaryClip(newEmptyClip)\n }\n //The delay after which the Clipboard is cleared, measured in seconds\n }, 5, TimeUnit.SECONDS)\n\n### Java\n\n //The Executor makes this task Asynchronous so that the UI continues being responsive\n\n ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor();\n\n backgroundExecutor.schedule(new Runnable() {\n @Override\n public void run() {\n //Creates a clip object with the content of the Clipboard\n ClipboardManager clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);\n ClipData clip = clipboard.getPrimaryClip();\n //If SDK version is higher or equal to 28, it deletes Clipboard data with clearPrimaryClip()\n if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.P) {\n clipboard.clearPrimaryClip();\n //If SDK version is lower than 28, it will replace Clipboard content with an empty value\n } else if (Build.VERSION.SDK_INT \u003c Build.VERSION_CODES.P) {\n ClipData newEmptyClip = ClipData.newPlainText(\"EmptyClipContent\", \"\");\n clipboard.setPrimaryClip(newEmptyClip);\n }\n //The delay after which the Clipboard is cleared, measured in seconds\n }, 5, TimeUnit.SECONDS);\n\nResources\n---------\n\n- [The clipboard framework](/develop/ui/views/touch-and-input/copy-paste#Clipboard)\n- [System notification shown when your app accesses clipboard data](/develop/ui/views/touch-and-input/copy-paste#PastingSystemNotifications)\n- [Add sensitive content to the clipboard](/develop/ui/views/touch-and-input/copy-paste#SensitiveContent)\n- [Privacy changes in Android 10](/about/versions/10/privacy/changes)\n- [Set app version information](/studio/publish/versioning#appversioning)"]]