Xử lý bảng nhớ tạm một cách an toàn
Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang
Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Danh mục OWASP: MASVS-CODE: Chất lượng mã
Tổng quan
Android cung cấp một khung mạnh mẽ được gọi là bảng nhớ tạm để sao chép và dán dữ liệu giữa các ứng dụng. Việc triển khai không đúng cách tính năng này có thể làm lộ dữ liệu liên quan đến người dùng cho các ứng dụng hoặc bên độc hại trái phép.
Rủi ro cụ thể liên quan đến việc tiết lộ dữ liệu bảng nhớ tạm phụ thuộc vào bản chất của ứng dụng và Thông tin nhận dạng cá nhân (PII) mà ứng dụng đó đang xử lý. Mức độ tác động đặc biệt cao đối với các ứng dụng tài chính, vì các ứng dụng này có thể hiển thị dữ liệu thanh toán hoặc các ứng dụng xử lý mã xác thực hai yếu tố (2FA).
Các vectơ tấn công có thể được tận dụng để đánh cắp dữ liệu trên bảng nhớ tạm sẽ khác nhau tuỳ theo phiên bản Android:
- Các phiên bản Android cũ hơn Android 10 (API cấp 29) cho phép các ứng dụng chạy ở chế độ nền truy cập vào thông tin bảng nhớ tạm của ứng dụng chạy ở chế độ nền trước, có thể cho phép các tác nhân độc hại truy cập trực tiếp vào mọi dữ liệu đã sao chép.
- Kể từ Android 12 trở lên (API cấp 31), mỗi khi một ứng dụng truy cập vào dữ liệu trong bảng nhớ tạm và dán dữ liệu đó, một thông báo ngắn sẽ hiển thị cho người dùng, khiến các cuộc tấn công khó bị bỏ qua hơn. Ngoài ra, để bảo vệ PII, Android hỗ trợ cờ đặc biệt
ClipDescription.EXTRA_IS_SENSITIVE
hoặc android.content.extra.IS_SENSITIVE
. Điều này cho phép nhà phát triển làm rối mã nguồn của bản xem trước nội dung bảng nhớ tạm trong giao diện người dùng đồ hoạ của bàn phím, ngăn dữ liệu đã sao chép hiển thị dưới dạng văn bản thô và có thể bị các ứng dụng độc hại đánh cắp. Việc không triển khai một trong các cờ nêu trên thực tế có thể cho phép kẻ tấn công đánh cắp dữ liệu nhạy cảm được sao chép vào bảng nhớ tạm bằng cách xem trộm hoặc thông qua các ứng dụng độc hại. Trong khi chạy ở chế độ nền, các ứng dụng này sẽ chụp ảnh màn hình hoặc quay video về hoạt động của người dùng hợp pháp.
Tác động
Việc khai thác hoạt động xử lý bảng nhớ tạm không đúng cách có thể dẫn đến việc dữ liệu tài chính hoặc dữ liệu nhạy cảm liên quan đến người dùng bị các tác nhân độc hại đánh cắp. Điều này có thể giúp kẻ tấn công thực hiện các hành động khác như chiến dịch giả mạo hoặc đánh cắp danh tính.
Giải pháp giảm thiểu
Gắn cờ dữ liệu nhạy cảm
Giải pháp này được dùng để làm rối mã nguồn của bản xem trước nội dung trên bảng nhớ tạm trong giao diện người dùng đồ hoạ của bàn phím. Mọi dữ liệu nhạy cảm có thể sao chép, chẳng hạn như mật khẩu hoặc dữ liệu thẻ tín dụng, phải được gắn cờ bằng ClipDescription.EXTRA_IS_SENSITIVE
hoặc android.content.extra.IS_SENSITIVE
trước khi gọi ClipboardManager.setPrimaryClip()
.
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);
Thực thi các phiên bản Android mới nhất
Việc thực thi ứng dụng chạy trên các phiên bản Android mới hơn hoặc bằng Android 10 (API 29) sẽ ngăn các quy trình ở chế độ nền truy cập vào dữ liệu bảng nhớ tạm trong ứng dụng trên nền trước.
Để buộc ứng dụng chỉ chạy trên Android 10 (API 29) trở lên, hãy đặt các giá trị sau cho chế độ cài đặt phiên bản trong tệp bản dựng Gradle trong dự án của bạn trong Android Studio.
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"
...
}
...
}
...
Xoá nội dung trên Bảng nhớ tạm sau một khoảng thời gian xác định
Nếu ứng dụng được thiết kế để chạy trên các phiên bản Android thấp hơn Android 10 (API cấp 29), thì mọi ứng dụng chạy nền đều có thể truy cập vào dữ liệu trên bảng nhớ tạm.
Để giảm rủi ro này, bạn nên triển khai một hàm xoá mọi dữ liệu được sao chép vào bảng nhớ tạm sau một khoảng thời gian cụ thể. Hàm này được tự động thực hiện kể từ Android 13 (API cấp 33).
Đối với các phiên bản Android cũ, bạn có thể thực hiện việc xoá này bằng cách đưa đoạn mã sau vào mã của ứng dụng.
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);
Tài nguyên
Nội dung và mã mẫu trên trang này phải tuân thủ các giấy phép như mô tả trong phần Giấy phép nội dung. Java và OpenJDK là nhãn hiệu hoặc nhãn hiệu đã đăng ký của Oracle và/hoặc đơn vị liên kết của Oracle.
Cập nhật lần gần đây nhất: 2025-07-26 UTC.
[[["Dễ hiểu","easyToUnderstand","thumb-up"],["Giúp tôi giải quyết được vấn đề","solvedMyProblem","thumb-up"],["Khác","otherUp","thumb-up"]],[["Thiếu thông tin tôi cần","missingTheInformationINeed","thumb-down"],["Quá phức tạp/quá nhiều bước","tooComplicatedTooManySteps","thumb-down"],["Đã lỗi thời","outOfDate","thumb-down"],["Vấn đề về bản dịch","translationIssue","thumb-down"],["Vấn đề về mẫu/mã","samplesCodeIssue","thumb-down"],["Khác","otherDown","thumb-down"]],["Cập nhật lần gần đây nhất: 2025-07-26 UTC."],[],[],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)"]]