添加额外的 HTTP 请求标头

帕沃尔·德罗塔尔
Pavol Drotar

HTTP 请求包含 User-Agent 或 Content-Type 等标头。除了浏览器附加的标头之外,Android 应用还可以通过 EXTRA_HEADERS intent extra 添加额外的标头,例如 Cookie 或引荐来源网址。出于安全考虑,Chrome 会根据 intent 的启动方式和位置过滤一些额外的标头。

跨域请求需要额外的安全层,因为客户端和服务器不属于同一方。本指南讨论了如何通过 Chrome 自定义标签页启动此类请求,即从可在浏览器标签页中打开网址的应用启动的 intent。在 Chrome 83 之前,开发者可以在启动自定义标签页时添加任何标题。从版本 83 开始,Chrome 开始滤除除已列入许可名单的跨源标头之外的所有标头,因为未列入许可名单的标头存在安全风险。从 Chrome 86 开始,当服务器和客户端使用数字资产链接关联时,可以将未列入许可名单的标头附加到跨源请求中。下表对这种行为进行了总结:

Chrome 版本 允许使用 CORS 标头
Chrome 83 之前的版本 已审批、未审批
Chrome 83 至 Chrome 85 已获得批准
从 Chrome 86 开始 已列入审批名单、未批准名单(已设置数字资产链接)

表 1.:过滤未批准的 CORS 标头。

本文介绍了如何在服务器与客户端之间设置经过验证的连接,并使用此连接发送已列入审批名单和未批准的 http 标头。您可以跳至向自定义标签页 intent 添加额外的标头以获取代码。

背景

已批准与未批准的 CORS 请求标头

跨域资源共享 (CORS) 允许一个来源的 Web 应用请求其他来源的资源。CORS 审批名单的标头列表在 HTML 标准中维护。下表显示的是已获得批准的标头示例:

标题 说明
接受-语言 宣传客户理解的自然语言
内容-语言 描述的是面向当前受众群体的语言
content-type 表示资源的媒体类型

表 2.:已获批的 CORS 标头示例。

获得批准的标头被视为安全的,因为它们不包含敏感的用户信息,并且不太可能导致服务器执行潜在的破坏性操作。

下表中列出了未获得批准的标头示例:

标题 说明
不记名令牌 在服务器上对客户端进行身份验证
表示请求的来源
饼干 包含由服务器设置的 Cookie

表 3.:未批准的 CORS 标头示例。

HTML 标准不建议将未获批准的标头附加到 CORS 请求中,并且服务器假定跨域请求仅包含已列入许可名单的标头。如果从跨源网域发送未列入许可名单的标头,则恶意第三方应用可能会创建标头来滥用 Chrome(或其他浏览器)存储并附加到请求中的用户 Cookie。这些 Cookie 可以对恶意服务器交易进行身份验证,而这些是无法通过其他方式实现的。

将 CORS 已批准的标头附加到自定义标签页请求

自定义标签页是一种在自定义浏览器标签页中启动网页的特殊方式。您可以使用 CustomTabsIntent.Builder() 创建自定义标签页 intent。您还可以使用带有 Browser.EXTRA_HEADERS 标志Bundle 将标头附加到这些 intent:

CustomTabsIntent intent = new CustomTabsIntent.Builder(session).build();

Bundle headers = new Bundle();
headers.putString("bearer-token", "Some token");
headers.putString("redirect-url", "Some redirect url");   
intent.intent.putExtra(Browser.EXTRA_HEADERS, headers);

intent.launchUrl(Activity.this, Uri.parse("http://www.google.com"));

我们始终可以将已列入批准的标头附加到自定义标签页 CORS 请求中。但是,Chrome 默认会过滤未批准的标头。虽然其他浏览器可能会有不同的行为,但开发者应该预料到,未列入许可名单的标头通常会被屏蔽。

在自定义标签页中添加未列入许可名单的标头支持的方法是,先使用数字访问链接验证跨源连接。下一部分将介绍如何设置这些内容,以及如何启动包含所需标头的自定义标签页 intent。

向自定义标签页 intent 添加额外的标头

若要允许通过自定义标签页 intent 传递未获得批准的标头,需要在 Android 与 Web 应用之间设置一个数字资产链接,用于验证作者是否拥有这两个应用。

请按照官方指南设置 Digital Asset Links。对于关联关系,请使用“delegate_permission/common.use_as_origin”,这表示在验证链接后,两个应用属于同一来源。

创建带有额外标头的自定义标签页 intent

您可以通过多种方式创建自定义标签页 intent。您可以通过将库添加到 build 依赖项来使用 androidX 中提供的构建器:

MULTI_LINE_CODE_PLACEHOLDER_1

构建 intent 并添加额外的标头:

MULTI_LINE_CODE_PLACEHOLDER_2

自定义标签页连接用于在应用和 Chrome 标签页之间设置 CustomTabsSession。我们需要该会话来验证应用和 Web 应用是否属于同一来源。仅当数字资产链接设置正确时,才会通过验证。

建议调用 CustomTabsClient.warmup()。它允许浏览器应用在后台预初始化,并加快网址打开过程。

MULTI_LINE_CODE_PLACEHOLDER_3

设置用于在验证后启动 intent 的回调

CustomTabsCallback 已传递到会话中。我们设置其 onRelationshipValidationResult(),以在源验证成功后启动先前创建的 CustomTabsIntent

MULTI_LINE_CODE_PLACEHOLDER_4

绑定自定义标签页服务连接

绑定服务会启动服务,系统最终会调用连接的 onCustomTabsServiceConnected()。请务必适当地取消绑定该服务。绑定和解除绑定通常在 onStart()onStop() activity 生命周期方法中完成。

// Bind the custom tabs service connection.
// Call this in onStart()
CustomTabsClient.bindCustomTabsService(this,
    CustomTabsClient.getPackageName(MainActivity.this, null), connection);

// …
// Unbind the custom tabs service.
// Call this in onStop().
unbindService(connection);

演示应用代码

如需详细了解自定义标签页服务,请点击此处。如需获取可正常使用的示例应用,请参阅 android-browser-helper GitHub 代码库。

摘要

本指南介绍了如何向自定义标签页 CORS 请求添加任意标头。已批准的标头可以附加到每个自定义标签页 CORS 请求。未列入许可名单的标头通常在 CORS 请求中被视为不安全,并且默认情况下 Chrome 会过滤这些标头。只有同源的客户端和服务器才能附加这些凭据,并通过 Digital Asset Links 进行验证。