依赖项验证

遭到入侵的 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.xmlverification-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 中正常运行。