已遭入侵的 Gradle 依赖项会带来安全风险。恶意行为者可能会将修改过的依赖项注入到构建过程中,例如在依赖项解析期间通过中间人攻击进行注入。
如果构建依赖项(库)已遭入侵,它可能会影响您的应用在设备上的执行方式。如果插件依赖项已遭入侵,它可能会改变您的构建方式,甚至在构建机器上运行外部命令。
为了缓解此问题,您可以在构建中启用依赖项验证。
库校验和与签名
库作者可以提供两部分元数据,以帮助验证您下载的依赖项的真实性。您可以定义一个名为 gradle/verification-metadata.xml
的文件来指定您批准的值。它可能包含
校验和 - 工件的哈希值,可用于验证工件在传输过程中未损坏。如果校验和是从受信任的来源获取的,则表示工件未发生更改,从而减少中间人攻击。
缺点是,由于校验和是从工件计算得出的,因此它们会随着每个版本而变化,这要求您在升级时更新
gradle/verification-metadata.xml
。签名 - 允许依赖项用户为给定工件指定公钥,以验证此工件是由拥有该公钥且经过身份验证的库作者构建和签名的。这会增加库作者的工作量,但只要其私钥本身未遭入侵,签名就表明该库是合法的。
如果库作者使用相同的密钥签署工件的每个版本,则在您升级时无需更新
gradle/verification-metadata.xml
。
启用依赖项验证
Gradle 依赖项验证会在您的构建期间比较校验和与签名。
创建一个包含以下内容的 gradle/verification-metadata.xml
文件
<?xml version="1.0" encoding="UTF-8"?>
<verification-metadata
xmlns="https://schema.gradle.org/dependency-verification"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://schema.gradle.org/dependency-verification https://schema.gradle.org/dependency-verification/dependency-verification-1.3.xsd">
<configuration>
<!-- verify .pom and .module files -->
<verify-metadata>true</verify-metadata>
<!-- verify .asc PGP files that come with the artifacts -->
<verify-signatures>true</verify-signatures>
<!-- use human readable keyring format -->
<keyring-format>armored</keyring-format>
<!-- read keys in a local file, fewer requests to network -->
<key-servers enabled="false">
<key-server uri="https://keyserver.ubuntu.com"/>
<key-server uri="https://keys.openpgp.org"/>
</key-servers>
</configuration>
<components>
</components>
</verification-metadata>
这将作为起点,并会很快更新。
运行 ./gradlew assembleDebug
以查看这如何更改构建。您将看到类似以下的消息
* What went wrong:
Error resolving plugin [id: 'com.android.application', version: '8.7.3', apply: false]
> Dependency verification failed for configuration 'detachedConfiguration1'
One artifact failed verification: com.android.application.gradle.plugin-8.7.3.pom ...
This can indicate that a dependency has been compromised ...
Open this report for more details: .../dependency-verification-report.html
Gradle 正在告诉您,您正在引入未经明确批准的依赖项版本。
引导校验和和签名数据
您可以引导初始受信任的密钥和组件集。此过程会收集项目使用的所有库的当前签名和校验和。
通过运行以下命令生成初始元数据
./gradlew --write-verification-metadata pgp,sha256 --export-keys help
此命令告诉 Gradle 为此项目中使用的所有依赖项构建 PGP 密钥和回退校验和的列表。您将看到 verification-metadata.xml 文件发生更改,其中包含许多类似以下内容的条目
<trusted-key id="8461EFA0E74ABAE010DE66994EB27DB2A3B88B8B">
<trusting group="androidx.activity"/>
</trusted-key>
这告诉 Gradle,如果它看到来自 Maven 组 androidx.activity
的依赖项,它将确保随附的 .asc 文件(存储在仓库中的签名)与该密钥匹配。
引导过程还将生成 gradle/verification-keyring.keys
,其中包含您的构建使用的公共 PGP 密钥。将这两个文件都检入您的版本跟踪系统。任何修改 verification-metadata.xml
或 verification-keyring.keys
的未来更改都应仔细审查。
从受信任的密钥中剥离版本
签名密钥在库的不同版本之间很少改变。gradle/verification-metadata.xml
文件中生成的数据包含版本详细信息,这意味着您需要为每个新的依赖项版本重新添加密钥信息。
为了避免这种情况,并指定密钥适用于库的所有版本,请移除版本规范。
在 Android Studio 编辑器中,使用 Edit > Find > Replace...(编辑 > 查找 > 替换...),并使用正则表达式来替换受信任密钥的所有版本规范。
- 从:
<trusted-key(.*) version=\".*\"/>
- 到:
<trusted-key$1/>
Android Studio 同步
到目前为止,您的命令行构建可以正常工作,但如果您尝试在 Android Studio 中同步,则会看到类似以下内容的错误
A build operation failed.
Dependency verification failed for configuration ':app:detachedConfiguration3'
One artifact failed verification: gradle-8.10.2-src.zip (gradle:gradle:8.10.2) from repository Gradle distributions
If the artifacts are trustworthy, you will need to update the gradle/verification-metadata.xml file. For more on how to do this, please refer to https://docs.gradle.org.cn/8.10.2/userguide/dependency_verification.html#sec:troubleshooting-verification in the Gradle documentation.
Android Studio 想要下载 Gradle 源代码(以及其他源代码和文档)。解决此问题的最简单方法是信任所有源代码和 Javadoc。在 gradle/verification-metadata.xml
中添加 <trusted-artifacts>
<verification-metadata ...>
<configuration>
<trusted-artifacts>
<trust file=".*-javadoc[.]jar" regex="true"/>
<trust file=".*-sources[.]jar" regex="true"/>
<trust group="gradle" name="gradle"/>
</trusted-artifacts>
...
</configuration>
</verification-metadata>
您的构建现在可以从命令行和 Android Studio 正常工作。