# Google broke reCAPTCHA for de-googled Android users

> 来源：[HackerNews](https://reclaimthenet.org/google-broke-recaptcha-for-de-googled-android-users)

```markdown
# Google broke reCAPTCHA for de-googled Android users

> 当"去谷歌化"遭遇验证码壁垒：一场关于数字自主权与技术垄断的深层博弈

---

## 背景与概述

在移动互联网时代，Google 服务早已深度嵌入 Android 生态的毛细血管。从 Google Play 服务框架到 reCAPTCHA 验证系统，这些组件构成了现代 Android 应用的"默认基础设施"。然而，近年来随着隐私意识的觉醒，越来越多的用户和开发者开始尝试"去谷歌化"（de-googled）——使用如 LineageOS、GrapheneOS、/e/OS 等剥离 Google 服务的定制 ROM，以夺回对个人数据的控制权。

这一趋势本应是技术多元化的积极信号，却遭遇了意想不到的阻力。据 [Reclaim The Net](https://reclaimthenet.org/google-broke-recaptcha-for-de-googled-android-users) 报道，Google 近期对 reCAPTCHA 系统的调整，导致大量去谷歌化 Android 用户无法正常通过人机验证。这一事件迅速在 HackerNews 等技术社区引发热议，其核心矛盾直指一个尖锐问题：**当垄断性技术基础设施的"安全更新"恰好封堵了替代方案的生存空间，这究竟是技术演进的无心之失，还是生态锁定的有意为之？**

对于普通用户而言，reCAPTCHA 故障意味着无法登录银行应用、无法提交表单、甚至无法完成基本的网络操作；对于开发者而言，这则是一次关于第三方依赖风险的深刻警示。

---

## 核心内容

### 1. 故障现象：验证码无限循环与直接阻断

去谷歌化用户反馈的核心症状包括：reCAPTCHA 验证框持续加载、点击后无响应、或直接提示"您的设备可能存在安全风险"。部分场景下，用户被迫陷入"验证-失败-再验证"的死循环，完全无法继续操作流程。这与传统 reCAPTCHA 的"点击即过"或"图片识别"交互模式截然不同，更像是设备层面的信任评分直接触发了拒绝策略。

### 2. 触发机制：SafetyNet/Play Integrity API 的隐性依赖

reCAPTCHA 并非独立运作的验证码系统。在 Android 端，它深度依赖 Google 的 **SafetyNet Attestation API**（现已迁移至 **Play Integrity API**）来获取设备的"完整性证明"。这些 API 会检查设备是否：
- 拥有有效的 Google Play 服务
- 未解锁 Bootloader / 未获取 Root 权限
- 运行经过 Google 认证的 ROM

去谷歌化设备天然无法满足上述条件，导致完整性验证失败，进而触发 reCAPTCHA 的拒绝逻辑。

### 3. 时间线与影响范围

此次故障并非渐进式降级，而是具有明显的时间节点特征。社区报告显示，2024 年初起相关投诉激增，与 Google 加速推进 Play Integrity API 替代 SafetyNet 的时间线高度重合。受影响的应用涵盖金融、社交、电商等多个领域，且由于 reCAPTCHA 的广泛嵌入，用户往往难以定位问题根源。

### 4. Google 的官方立场与社区质疑

Google 将此类问题归类为"预期的安全行为"，强调 Play Integrity API 旨在保护应用免受篡改和欺诈。然而批评者指出，这种"一刀切"的策略将隐私导向的合法用户与真正的恶意行为者混为一谈，实质上构成了对替代 ROM 生态的技术歧视。

### 5. 与 Web 端 reCAPTCHA 的关键差异

值得区分的是，桌面浏览器端的 reCAPTCHA v2/v3 主要基于行为分析和 Cookie 画像，并不直接依赖本地 Google 服务。而 Android 端的集成由于应用沙箱和系统架构的特殊性，被迫将设备完整性验证作为前置条件——这一设计差异正是本次冲突的技术根源。

---

## 技术分析

### Play Integrity API 的验证流程

```kotlin
// 典型的 Play Integrity API 调用流程（简化示意）
val integrityManager = IntegrityManagerFactory.create(context)

val request = IntegrityTokenRequest.builder()
    .setNonce(generateNonce())  // 服务端生成的防重放随机数
    .build()

integrityManager.requestIntegrityToken(request)
    .addOnSuccessListener { response ->
        val integrityToken = response.token()
        // 发送至服务端验证
        verifyWithGoogleServer(integrityToken)
    }
    .addOnFailureListener { exception ->
        // 去谷歌化设备通常在此触发异常
        handleIntegrityFailure(exception)
    }
```

服务端验证返回的 JSON 包含关键字段 `deviceRecognitionVerdict`，其典型值包括：
- `MEETS_DEVICE_INTEGRITY`：通过全部检查
- `MEETS_BASIC_INTEGRITY`：仅通过基础检查（Bootloader 可能已解锁）
- 空值或缺失：未通过任何检查

reCAPTCHA 的 Android SDK 在底层封装了上述流程，当识别到非 `MEETS_DEVICE_INTEGRITY` 状态时，即可能拒绝服务。

### 去谷歌化设备的"指纹"暴露

即使通过 MicroG 等开源实现模拟 Google 服务，以下特征仍可能导致识别：

| 检测维度 | 去谷歌化设备特征 | 正常设备特征 |
|---------|--------------|-----------|
| 签名验证 | 无法通过 Google 私钥签名验证 | 内置 Google 根证书 |
| 硬件证明 | 缺少 TPM/TEE 的 OEM 密钥认证 | 厂商预置安全元件 |
| 系统属性 | `ro.build.tags=test-keys` 等 | `release-keys` |
| 网络端点 | 连接至 MicroG 自定义服务器 | 直连 Google 服务器 |

### 架构层面的依赖陷阱

```
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   应用层 (App)   │────→│  reCAPTCHA SDK  │────→│ Play Integrity  │
│                 │     │   (Google 私有)   │     │    API Server   │
└─────────────────┘     └─────────────────┘     └─────────────────┘
                              │                          │
                              ↓                          ↓
                        ┌─────────────┐           ┌─────────────┐
                        │  SafetyNet/  │           │  Google 设备 │
                        │ Play Integrity│←────────→│  认证数据库  │
                        │  (本地服务)   │           │             │
                        └─────────────┘           └─────────────┘
                              ↑
                              │
                        ┌─────────────┐
                        │  去谷歌化设备  │
                        │ (MicroG/无服务)│
                        └─────────────┘
                              ↓
                        [完整性验证失败]
```

此架构的核心问题在于：**验证信任链的单点故障**。一旦 Google 服务端策略收紧，整个下游生态无替代路径可走。

---

## 实践建议

### 对应用开发者

**1. 实施渐进式降级策略**

避免将 Play Integrity 作为唯一验证手段，可结合多因素评估：

```kotlin
fun assessDeviceTrust(context: Context): TrustLevel {
    return when {
        // 优先尝试 Play Integrity
        playIntegrityAvailable() && passesFullIntegrityCheck() -> TrustLevel.HIGH
        // 降级至基础完整性
        passesBasicIntegrityCheck() -> TrustLevel.MEDIUM
        // 最终 fallback：应用层行为挑战
        else -> TrustLevel.LOW // 触发备用验证（如邮箱验证码、短信验证）
    }
}
```

**2. 提供明确的错误引导**

当检测到完整性失败时，避免模糊提示，应区分"设备不支持"与"安全风险"场景：

```xml
<!-- strings.xml -->
<string name="integrity_unsupported">
    您的设备未通过 Google Play 完整性验证。这可能是因为：
    \n• 使用了定制 ROM 或去谷歌化系统
    \n• 设备已 Root 或解锁 Bootloader
    \n\n您仍可继续使用基础功能，部分安全敏感操作可能需要额外验证。
</string>
```

**3. 评估替代验证方案**

| 方案 | 适用场景 | 隐私特性 | 集成复杂度 |
|-----|---------|---------|----------|
| hCaptcha | 通用验证码 | 较好 | 低 |
| Cloudflare Turnstile | 无感验证 | 优秀 | 低 |
| 自建行为分析 | 高安全场景 | 完全可控 | 高 |
| WebAuthn/通行密钥 | 身份验证替代 | 优秀 | 中 |

### 对去谷歌化用户

- **临时方案**：通过浏览器访问 Web 版服务（绕过 Android SDK 的完整性检查）
- **进阶方案**：配置 MicroG 的 SafetyNet 代理，但需注意其有效性随 Google 策略更新而波动
- **长期关注**：支持采用开放标准的应用，推动开发者减少对专有完整性 API 的依赖

### 对 ROM 发行版

考虑预装或推荐 [Plexus](https://plexus.techlore.tech/) 等兼容性数据库，帮助用户预判应用运行状况，降低挫败感。

---

## 总结

reCAPTCHA 对去谷歌化设备的"误伤"，表面是一次技术兼容性问题，实则揭示了当代数字基础设施中**开放性承诺与商业控制张力**的深层结构。当"保护用户安全"的叙事与"维护平台垄断"的实践难以清晰界分时，开发者与用户的每一次技术选择都在参与塑造未来的权力格局。对于中国的技术社区而言，这一案例尤为值得镜鉴：在构建自主可控的移动生态过程中，如何避免重蹈"以安全之名行封闭之实"的覆辙，如何在便利与自由之间寻求动态平衡，将是超越具体技术栈