Kategori OWASP: MASVS-CODE: Kualitas Kode
Ringkasan
Memuat kode secara dinamis ke dalam aplikasi menimbulkan tingkat risiko yang harus dimitigasi. Penyerang berpotensi merusak atau mengganti kode untuk mengakses data sensitif atau menjalankan tindakan berbahaya.
Banyak bentuk pemuatan kode dinamis, terutama yang menggunakan sumber jarak jauh, melanggar kebijakan Google Play dan dapat menyebabkan penangguhan aplikasi Anda dari Google Play.
Dampak
Jika penyerang berhasil mendapatkan akses ke kode yang akan dimuat ke dalam aplikasi, mereka dapat mengubahnya untuk mendukung tujuan mereka. Hal ini dapat menyebabkan pemindahan data secara tidak sah dan eksploitasi eksekusi kode. Meskipun penyerang tidak dapat mengubah kode untuk melakukan tindakan arbitrer pilihan mereka, mereka masih dapat merusak atau menghapus kode dan dengan demikian memengaruhi ketersediaan aplikasi.
Mitigasi
Hindari penggunaan pemuatan kode dinamis
Kecuali ada kebutuhan bisnis, hindari pemuatan kode dinamis. Sebaiknya sertakan semua fungsi langsung ke dalam aplikasi, jika memungkinkan.
Gunakan sumber tepercaya
Kode yang akan dimuat ke dalam aplikasi harus disimpan di lokasi tepercaya. Untuk penyimpanan lokal, penyimpanan internal aplikasi atau penyimpanan terbatas (untuk Android 10 dan yang lebih baru) adalah tempat yang direkomendasikan. Lokasi ini memiliki langkah-langkah untuk menghindari akses langsung dari aplikasi dan pengguna lain.
Saat memuat kode dari lokasi jarak jauh seperti URL, hindari penggunaan pihak ketiga jika memungkinkan, dan simpan kode di infrastruktur Anda sendiri, dengan mengikuti praktik terbaik keamanan. Jika Anda perlu memuat kode pihak ketiga, pastikan penyedia tersebut tepercaya.
Lakukan pemeriksaan integritas
Pemeriksaan integritas direkomendasikan untuk memastikan kode tidak dirusak. Pemeriksaan ini harus dilakukan sebelum memuat kode ke dalam aplikasi.
Saat memuat resource jarak jauh, integritas subresource dapat digunakan untuk memvalidasi integritas resource yang diakses.
Saat memuat resource dari penyimpanan eksternal, gunakan pemeriksaan integritas untuk memverifikasi bahwa tidak ada aplikasi lain yang merusak data atau kode ini. Hash file harus disimpan dengan aman, sebaiknya dienkripsi dan di penyimpanan internal.
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(bytes.length * 2)
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(bytes.length * 2);
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!");
}
}
}
Tandatangani kode
Opsi lain untuk memastikan integritas data adalah menandatangani kode dan memverifikasi tanda tangannya sebelum memuatnya. Metode ini memiliki keunggulan karena juga memastikan integritas kode hash, bukan hanya kode itu sendiri, yang memberikan perlindungan tambahan terhadap perusakan.
Meskipun penandatanganan kode memberikan lapisan keamanan tambahan, penting untuk diperhatikan bahwa proses ini lebih kompleks dan mungkin memerlukan upaya dan resource tambahan agar berhasil diterapkan.
Beberapa contoh penandatanganan kode dapat ditemukan di bagian Resource dokumen ini.
Resource
- Integritas Subresource
- Menandatangani Data Secara Digital
- Penandatanganan Kode
- Data Sensitif yang Disimpan di Penyimpanan Eksternal