动态代码加载
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
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 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-07-26。
[null,null,["最后更新时间 (UTC):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)"]]