Danh mục OWASP: MASVS-STORAGE: Bộ nhớ
Tổng quan
Các ứng dụng nhắm đến Android 10 (API 29) trở xuống không bắt buộc phải sử dụng bộ nhớ có giới hạn. Điều này có nghĩa là mọi ứng dụng khác có quyền READ_EXTERNAL_STORAGE đều có thể truy cập vào mọi dữ liệu được lưu trữ trên bộ nhớ ngoài.
Tác động
Trong các ứng dụng nhắm đến Android 10 (API 29) trở xuống, nếu dữ liệu nhạy cảm được lưu trữ trên bộ nhớ ngoài, thì mọi ứng dụng trên thiết bị có quyền READ_EXTERNAL_STORAGE đều có thể truy cập vào dữ liệu đó. Điều này cho phép các ứng dụng độc hại truy cập âm thầm vào các tệp nhạy cảm được lưu trữ vĩnh viễn hoặc tạm thời trên bộ nhớ ngoài. Ngoài ra, vì mọi ứng dụng trên hệ thống đều có thể truy cập vào nội dung trên bộ nhớ ngoài, nên mọi ứng dụng độc hại cũng khai báo quyền WRITE_EXTERNAL_STORAGE đều có thể giả mạo các tệp được lưu trữ trên bộ nhớ ngoài, chẳng hạn như để đưa dữ liệu độc hại vào. Nếu được tải vào ứng dụng, dữ liệu độc hại này có thể được thiết kế để lừa người dùng hoặc thậm chí thực thi mã.
Giải pháp giảm thiểu
Bộ nhớ có giới hạn (Android 10 trở lên)
Android 10
Đối với các ứng dụng nhắm đến Android 10, nhà phát triển có thể chọn sử dụng bộ nhớ có giới hạn một cách rõ ràng. Bạn có thể thực hiện việc này bằng cách đặt cờ requestLegacyExternalStorage thành false trong tệp AndroidManifest.xml. Với bộ nhớ có giới hạn, các ứng dụng chỉ có thể truy cập vào những tệp mà chúng đã tự tạo trên bộ nhớ ngoài hoặc các loại tệp được lưu trữ bằng API MediaStore, chẳng hạn như Âm thanh và Video. Điều này giúp bảo vệ quyền riêng tư và bảo mật của người dùng.
Android 11 trở lên
Đối với các ứng dụng nhắm đến Android 11 trở lên, hệ điều hành buộc phải sử dụng bộ nhớ có giới hạn, tức là hệ điều hành sẽ bỏ qua cờ requestLegacyExternalStorage và tự động bảo vệ bộ nhớ ngoài của ứng dụng khỏi bị truy cập trái phép.
Sử dụng bộ nhớ trong cho dữ liệu nhạy cảm
Bất kể phiên bản Android mục tiêu là gì, dữ liệu nhạy cảm của ứng dụng luôn phải được lưu trữ trên bộ nhớ trong. Quyền truy cập vào bộ nhớ trong sẽ tự động bị hạn chế đối với ứng dụng sở hữu nhờ tính năng hộp cát của Android. Do đó, bộ nhớ trong có thể được coi là an toàn, trừ phi thiết bị đã bị can thiệp vào hệ thống.
Mã hoá dữ liệu nhạy cảm
Nếu các trường hợp sử dụng của ứng dụng yêu cầu lưu trữ dữ liệu nhạy cảm trên bộ nhớ ngoài, thì dữ liệu đó phải được mã hoá. Bạn nên sử dụng một thuật toán mã hoá mạnh, dùng Android KeyStore để lưu trữ khoá một cách an toàn.
Nói chung, mã hoá tất cả dữ liệu nhạy cảm là một biện pháp bảo mật nên áp dụng, bất kể dữ liệu đó được lưu trữ ở đâu.
Điều quan trọng cần lưu ý là phương thức mã hoá toàn bộ đĩa (hoặc phương thức mã hoá dựa trên tệp từ Android 10) là một biện pháp nhằm bảo vệ dữ liệu khỏi truy cập thực tế và các vector tấn công khác. Do đó, để cấp cùng một biện pháp bảo mật, ứng dụng cũng nên mã hoá dữ liệu nhạy cảm được lưu trữ trên bộ nhớ ngoài.
Thực hiện kiểm tra tính toàn vẹn
Trong trường hợp dữ liệu hoặc mã phải được tải từ bộ nhớ ngoài vào ứng dụng, bạn nên kiểm tra tính toàn vẹn để xác minh rằng không có ứng dụng nào khác can thiệp vào dữ liệu hoặc mã này. Bạn nên lưu trữ hàm băm của các tệp một cách an toàn, tốt nhất là mã hoá và lưu trữ trong bộ nhớ trong.
Kotlin
package com.example.myapplication
import java.io.BufferedInputStream
import java.io.FileInputStream
import java.io.IOException
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
object FileIntegrityChecker {
@Throws(IOException::class, NoSuchAlgorithmException::class)
fun getIntegrityHash(filePath: String?): String {
val md = MessageDigest.getInstance("SHA-256") // You can choose other algorithms as needed
val buffer = ByteArray(8192)
var bytesRead: Int
BufferedInputStream(FileInputStream(filePath)).use { fis ->
while (fis.read(buffer).also { bytesRead = it } != -1) {
md.update(buffer, 0, bytesRead)
}
}
private fun bytesToHex(bytes: ByteArray): String {
val sb = StringBuilder()
for (b in bytes) {
sb.append(String.format("%02x", b))
}
return sb.toString()
}
@Throws(IOException::class, NoSuchAlgorithmException::class)
fun verifyIntegrity(filePath: String?, expectedHash: String): Boolean {
val actualHash = getIntegrityHash(filePath)
return actualHash == expectedHash
}
@Throws(Exception::class)
@JvmStatic
fun main(args: Array<String>) {
val filePath = "/path/to/your/file"
val expectedHash = "your_expected_hash_value"
if (verifyIntegrity(filePath, expectedHash)) {
println("File integrity is valid!")
} else {
println("File integrity is compromised!")
}
}
}
Java
package com.example.myapplication;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class FileIntegrityChecker {
public static String getIntegrityHash(String filePath) throws IOException, NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256"); // You can choose other algorithms as needed
byte[] buffer = new byte[8192];
int bytesRead;
try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(filePath))) {
while ((bytesRead = fis.read(buffer)) != -1) {
md.update(buffer, 0, bytesRead);
}
}
byte[] digest = md.digest();
return bytesToHex(digest);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public static boolean verifyIntegrity(String filePath, String expectedHash) throws IOException, NoSuchAlgorithmException {
String actualHash = getIntegrityHash(filePath);
return actualHash.equals(expectedHash);
}
public static void main(String[] args) throws Exception {
String filePath = "/path/to/your/file";
String expectedHash = "your_expected_hash_value";
if (verifyIntegrity(filePath, expectedHash)) {
System.out.println("File integrity is valid!");
} else {
System.out.println("File integrity is compromised!");
}
}
}
Tài nguyên
- Bộ nhớ có giới hạn
- READ_EXTERNAL_STORAGE
- WRITE_EXTERNAL_STORAGE
- requestLegacyExternalStorage
- Tổng quan về lưu trữ dữ liệu và tệp
- Lưu trữ dữ liệu (Dành riêng cho ứng dụng)
- Mật mã học
- Kho khoá
- Mã hoá dựa trên tệp
- Mã hoá toàn bộ đĩa