動態程式碼載入
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
OWASP 類別:MASVS-CODE:程式碼品質
總覽
動態將程式碼載入應用程式會帶來風險,必須採取措施降低風險。攻擊者可能會竄改或替換程式碼,以便存取機密資料或執行有害動作。
許多形式的動態程式碼載入作業 (尤其是使用遠端來源的作業) 都違反 Google Play 政策,可能導致應用程式從 Google Play 停權。
影響
如果攻擊者成功取得將載入應用程式的程式碼存取權,就能修改程式碼以達成目標,進而導致資料外洩和程式碼執行漏洞。即使攻擊者無法修改程式碼來執行任意動作,仍有可能損毀或移除程式碼,進而影響應用程式的可用性。
因應措施
避免使用動態程式碼載入
除非有業務需求,否則請避免動態程式碼載入。建議您盡可能將所有功能直接納入應用程式。
使用可信賴的來源
要載入至應用程式的程式碼應儲存在可信任的位置。就本機儲存空間而言,我們建議使用應用程式內部儲存空間或限定範圍儲存空間 (適用於 Android 10 以上版本)。這些位置已採取措施,避免其他應用程式和使用者直接存取。
從網址等遠端位置載入程式碼時,請盡量避免使用第三方,並根據安全性最佳做法,將程式碼儲存在您自己的基礎架構中。如果您需要載入第三方程式碼,請確認供應商是可信任的供應商。
建議您進行完整性檢查,確保程式碼未遭竄改。應在將程式碼載入應用程式前執行這些檢查。
載入遠端資源時,可以使用子資源完整性來驗證所存取資源的完整性。
從外部儲存空間載入資源時,請使用完整性檢查來確認沒有其他應用程式竄改這項資料或程式碼。檔案的雜湊應以安全的方式儲存,最好是加密並儲存在內部儲存空間。
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!");
}
}
}
簽署驗證碼
另一種確保資料完整性的做法,是在載入程式碼前為其簽署並驗證簽名。這個方法的好處在於,除了程式碼本身,也能確保雜湊碼的完整性,因此可提供額外的防竄改保護機制。
雖然程式碼簽署可提供額外的安全層級,但請注意,這個程序比較複雜,可能需要額外努力和資源才能成功實作。
您可以在本文的「資源」部分找到一些程式碼簽署範例。
資源
這個頁面中的內容和程式碼範例均受《內容授權》中的授權所規範。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,["# Dynamic Code Loading\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-CODE: Code Quality](https://mas.owasp.org/MASVS/10-MASVS-CODE)\n\nOverview\n--------\n\nDynamically loading code into an application introduces a risk level that has to\nbe mitigated. Attackers could potentially tamper with or substitute the code to\naccess sensitive data or execute harmful actions.\n\nMany forms of dynamic code loading, especially those that use remote sources,\n[violate Google Play policies](https://support.google.com/googleplay/android-developer/answer/9888379) and may lead to a suspension of your app from\nGoogle Play.\n\nImpact\n------\n\nIf attackers manage to gain access to the code that will be loaded into the\napplication, they could modify it to support their goals. This could lead to\ndata exfiltration and code execution exploits. Even if attackers cannot modify\nthe code to perform arbitrary actions of their choice, it is still possible that\nthey can corrupt or remove the code and thus affect the availability of the\napplication.\n\nMitigations\n-----------\n\n### Avoid using dynamic code loading\n\nUnless there is a business need, avoid dynamic code loading. You should prefer\nto include all functionalities directly into the application, whenever possible.\n\n### Use trusted sources\n\nCode that will be loaded into the application should be stored in trusted\nlocations. Regarding local storage, the application internal storage or scoped\nstorage (for Android 10 and later) are the recommended places. These locations\nhave measures to avoid direct access from other applications and users.\n\nWhen loading code from remote locations such as URLs, avoid using third parties\nwhen possible, and store the code in your own infrastructure, following security\nbest practices. If you need to load third-party code, ensure that the provider\nis a trusted one.\n\n### Perform integrity checks\n\nIntegrity checks are recommended in order to ensure that the code has not been\ntampered with. These checks should be performed before loading code into the\napplication.\n\nWhen loading remote resources, subresource integrity can be used in order to\nvalidate the integrity of the accessed resources.\n\nWhen loading resources from the external storage, use integrity checks to verify\nthat no other application has tampered with this data or code. The hashes of the\nfiles should be stored in a secure manner, preferably encrypted and in the\ninternal storage. \n\n### Kotlin\n\n package com.example.myapplication\n\n import java.io.BufferedInputStream\n import java.io.FileInputStream\n import java.io.IOException\n import java.security.MessageDigest\n import java.security.NoSuchAlgorithmException\n\n object FileIntegrityChecker {\n @Throws(IOException::class, NoSuchAlgorithmException::class)\n fun getIntegrityHash(filePath: String?): String {\n val md = MessageDigest.getInstance(\"SHA-256\") // You can choose other algorithms as needed\n val buffer = ByteArray(8192)\n var bytesRead: Int\n BufferedInputStream(FileInputStream(filePath)).use { fis -\u003e\n while (fis.read(buffer).also { bytesRead = it } != -1) {\n md.update(buffer, 0, bytesRead)\n }\n\n }\n\n private fun bytesToHex(bytes: ByteArray): String {\n val sb = StringBuilder(bytes.length * 2)\n for (b in bytes) {\n sb.append(String.format(\"%02x\", b))\n }\n return sb.toString()\n }\n\n @Throws(IOException::class, NoSuchAlgorithmException::class)\n fun verifyIntegrity(filePath: String?, expectedHash: String): Boolean {\n val actualHash = getIntegrityHash(filePath)\n return actualHash == expectedHash\n }\n\n @Throws(Exception::class)\n @JvmStatic\n fun main(args: Array\u003cString\u003e) {\n val filePath = \"/path/to/your/file\"\n val expectedHash = \"your_expected_hash_value\"\n if (verifyIntegrity(filePath, expectedHash)) {\n println(\"File integrity is valid!\")\n } else {\n println(\"File integrity is compromised!\")\n }\n }\n }\n\n### Java\n\n package com.example.myapplication;\n\n import java.io.BufferedInputStream;\n import java.io.FileInputStream;\n import java.io.IOException;\n import java.security.MessageDigest;\n import java.security.NoSuchAlgorithmException;\n\n public class FileIntegrityChecker {\n\n public static String getIntegrityHash(String filePath) throws IOException, NoSuchAlgorithmException {\n MessageDigest md = MessageDigest.getInstance(\"SHA-256\"); // You can choose other algorithms as needed\n byte[] buffer = new byte[8192];\n int bytesRead;\n\n try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(filePath))) {\n while ((bytesRead = fis.read(buffer)) != -1) {\n md.update(buffer, 0, bytesRead);\n }\n }\n\n byte[] digest = md.digest();\n return bytesToHex(digest);\n }\n\n private static String bytesToHex(byte[] bytes) {\n StringBuilder sb = new StringBuilder(bytes.length * 2);\n for (byte b : bytes) {\n sb.append(String.format(\"%02x\", b));\n }\n return sb.toString();\n }\n\n public static boolean verifyIntegrity(String filePath, String expectedHash) throws IOException, NoSuchAlgorithmException {\n String actualHash = getIntegrityHash(filePath);\n return actualHash.equals(expectedHash);\n }\n\n public static void main(String[] args) throws Exception {\n String filePath = \"/path/to/your/file\";\n String expectedHash = \"your_expected_hash_value\";\n\n if (verifyIntegrity(filePath, expectedHash)) {\n System.out.println(\"File integrity is valid!\");\n } else {\n System.out.println(\"File integrity is compromised!\");\n }\n }\n }\n\n### Sign the code\n\nAnother option to ensure the integrity of the data is to sign the code and\nverify its signature before loading it. This method has the advantage of also\nensuring the integrity of the hash code, not only the code itself, which\nprovides an additional anti-tampering protection.\n\nAlthough code signing provides additional security layers, it is important to\ntake into account that it is a more complex process that may require additional\neffort and resources to be successfully implemented.\n\nSome examples of code signing can be found in the Resources section of this\ndocument.\n\nResources\n---------\n\n- [Subresource Integrity](https://en.wikipedia.org/wiki/Subresource_Integrity)\n- [Digitally Sign Data](https://developers.google.com/tink/digitally-sign-data#java)\n- [Code Signing](https://en.wikipedia.org/wiki/Code_signing)\n- [Sensitive Data Stored in External Storage](/privacy-and-security/risks/sensitive-data-external-storage)"]]