遭到入侵的 Gradle 依赖项会带来安全风险。恶意攻击者可能会将经过修改的依赖项注入构建流程,例如,在依赖项解析期间通过中间人攻击。
如果构建依赖项(库)遭到入侵,可能会影响应用在设备上的执行方式。如果插件依赖项遭到入侵,可能会改变 build 的工作方式,甚至在 build 机上运行外部命令。
为缓解此问题,您可以在 build 中启用依赖项验证。
库校验和和签名
库作者可以提供两项元数据,这两项元数据有助于验证您下载的依赖项的真实性。您可以定义一个名为 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
,看看这会对 build 产生怎样的影响。您会看到以下类似消息
* 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
,其中包含 build 使用的 PGP 公钥。将这两个文件都签入到版本跟踪系统中。未来,如果要修改 verification-metadata.xml
或 verification-keyring.keys
,请务必仔细检查。
从可信密钥中移除版本
库的不同版本之间的签名密钥很少发生变化。gradle/verification-metadata.xml
文件中生成的数据包含版本详细信息,这意味着您需要为每个新依赖项版本重新添加关键信息。
为避免出现这种情况,并指定密钥适用于库的所有版本,请移除版本规范。
在 Android Studio 编辑器中,依次选择 Edit > Find > Replace...,使用正则表达式替换可信密钥的所有版本规范。
- 起始位置:
<trusted-key(.*) version=\".*\"/>
- 收件人:
<trusted-key$1/>
Android Studio 同步
到目前为止,您的命令行 build 可以正常运行,但如果您尝试在 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/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>
现在,您的 build 将能够在命令行和 Android Studio 中正常运行。