网页功能可能无法按预期工作

Avatar of Farai Gandiya
Farai Gandiya

DigitalOcean 为您的旅程各个阶段提供云产品。立即开始使用 $200 免费积分!

随着网络功能越来越强大,开发人员能够创造更丰富的在线体验。但是,有时出于可用性、安全性和隐私的考虑,一些新的网络功能可能无法按预期工作。

我遇到过这样的情况。例如 HTML 中的延迟加载。只需将该属性添加到图像元素上,您可能会发现它实际上需要更多操作才能实现其功能。当我们研究一些可能无法完全按预期工作的其他功能时,我们将详细介绍这个特定功能。

这个限制已经存在了一段时间,但它确实展示了浏览器功能如何被利用。一种可能的利用方式是,一个锚点在 CSS 中获得了 :visited 链接样式,并被放置在屏幕外。使用屏幕外的锚点,可以使用 JavaScript 更改锚点的 href 值,并查看特定的 href 是否会导致链接显示为已访问,从而在过程中重建用户的历史记录。

这被称为 CSS 历史记录泄漏,曾经非常普遍,以至于美国联邦贸易委员会(美国消费者保护机构)对利用该漏洞的行为处以重罚.

如今,尝试在 :visited 链接上使用 getComputedStyle 会返回未访问(:link)链接的样式。这是您必须了解的事情之一,因为它与直观的预期工作方式不同。

您可以尝试两种方法来解决这个问题,但两种方法都不可行。

  1. 使已访问链接的样式触发副作用(例如布局变化),或者
  2. 利用兄弟(~+)或子级(>)CSS 选择器来渲染另一种样式。

关于副作用,虽然有 一些巧妙但脆弱的方法可以实现这一点,但我们用来 设置 :visited 链接样式的选项有限,某些样式(如 background-color)只有在应用于未访问链接时才能生效。至于使用兄弟或子级,对这些元素执行 getComputedStyle 会返回样式,就好像链接从未被访问过一样。

浏览器不再跨站点缓存资产

CDN 的一个优势是它们允许在浏览器中缓存特定资源(例如 Google Fonts),以便在不同网站之间使用。虽然这确实能带来很大的性能提升,但它也存在严重的隐私问题。

考虑到已缓存的资产加载时间比未缓存的资产更长,网站可以执行 计时攻击,不仅可以查看您的网站历史记录,还可以暴露您的身份和在线活动。 Jeff Kaufman 给出了一个例子

不幸的是,共享缓存会导致隐私泄漏。以下是简单版本总结

  • 我想知道您是否在 www.forum.example 上是版主。
  • 我知道只有在加载 www.forum.example/moderators/header.css 的页面下。
  • 当您访问我的页面时,我加载 www.forum.example/moderators/header.css 并查看它是否来自缓存。

鉴于此,浏览器不再提供这种功能。

performance.now() 可能不准确

几年前出现了一组可怕的漏洞,其中之一被称为 幽灵。有关深入解释,请参阅 Google 的 leaky.page(在 Chromium 中效果最佳)作为概念验证。但对于本文而言,只需知道该漏洞依赖于获得高度准确的计时(这是 performance.now() 提供的),以尝试映射敏感的 CPU 数据。

Text about the demo on the left side of the page and two black Germaine-looking code blocks on the right side with a black background and green text.
:https://leaky.page 上的演示

为了缓解幽灵漏洞,浏览器降低了其准确性,并可能添加噪声。这些范围从 20μs 到 1ms,并且可能会根据各种条件(如 HTTP 标头和浏览器设置)进行更改。

loading 属性的延迟加载在没有 JavaScript 的情况下不起作用

延迟加载 是一种技术,它只在资产滚动到视窗时才在浏览器中加载资产。直到最近,我们只能使用 JavaScript 来实现这一点,使用的是 IntersectionObserveronscroll。除了 Safari,我们可以将 loading 属性应用于图像和 iframe(在 Chromium 中),浏览器将处理延迟加载。

请注意,延迟加载不能被 polyfilled,因为当您检查 loading 属性的支持时,图像可能已经加载完毕。

能够在 HTML 中执行此操作使其听起来像是该属性根本不需要 JavaScript,但实际上需要。来自 WHATWG 规范

  1. 如果元素禁用了脚本,则返回 false。

    注意
    这是一项反跟踪措施,因为如果用户代理在禁用脚本的情况下支持延迟加载,那么网站仍然可以通过在页面标记中战略性地放置图像来跟踪用户的大致滚动位置,这样服务器可以跟踪请求了多少图像以及何时请求。

我看到一些文章提到,这种属性是您“无需 JavaScript”支持延迟加载的方式,这并不正确,虽然您确实不需要编写任何代码。

浏览器可以根据用户偏好限制功能

出于进一步的安全性和隐私考虑,一些用户可能会选择严格限制浏览器功能。Firefox 和 Tor 是两个通过 抵抗指纹设置 来执行此操作的浏览器,它们会执行诸如降低某些变量(尺寸和时间)的精度、完全省略某些变量、限制或禁用某些 Web API 以及从不匹配媒体查询等操作。WebKit 有一份文件概述了 浏览器如何实现指纹抵抗.

请注意,这超出了浏览器实施的标准反跟踪功能。用户不太可能启用此功能,因为他们需要非常具体的威胁模型才能这样做。可以通过渐进增强、优雅降级和了解您的用户来部分抵消这种情况。当您确实需要指纹识别时(例如欺诈检测),这种限制是一个大问题。因此,如果绝对有必要,请寻找替代方法。

屏幕阅读器可能无法传递某些元素的语义

语义化 HTML 非常棒,原因有很多,最值得注意的是它在标记中传达了意义,软件(如屏幕阅读器)可以解释并向依赖它们浏览网页的用户宣布这些意义。对于制作可访问的网站来说,这是必不可少的。但是,有时这些语义不会被传递——至少不像您预期的那样。某些东西可能可访问,但仍然存在可用性问题。

一个例子是,在启用 VoiceOver 的 WebKit 中,删除列表的标记会删除其语义意义。这是一种非常常见的模式,最显著的是用于站点导航。苹果可访问性标准经理 James Craig 解释了为什么这是一个可用性问题,引用了 W3C 的组成部分优先级设计原则

如果发生冲突,应优先考虑用户,然后是作者、实现者、规范者,最后是理论纯度。换句话说,**用户成本或困难应该比作者成本更重要**;

另一个语义可能无法传达的例子是强调。以内联元素为例,例如strongemmarkinsdeldata——这些元素都具有语义含义,但不太可能被读出来,因为它们会变得很吵。这可以在用户的屏幕阅读器设置中更改,但如果你真的希望它被读出来,你可以使用:before:after伪元素的content属性将其声明为视觉隐藏

为了说明这一点,我制作了一个简短的示例,以查看 NVDA 与 Firefox 89 和 VoiceOver 与 Safari 14.6 如何读出语义元素。

与 VoiceOver 不同,NVDA 读出了一些语义元素(delinsmark),并试图通过逐渐提高强调文本的音量来强调文本。然而,它们都能够轻松读出:before/:after伪元素。此外,VoiceOver 读出了标签的括号(大于号、小于号),虽然这两个屏幕阅读器都具有更改读取多少标点符号的能力。

要查看你是否需要强调强调,请确保与你的用户进行测试,并查看他们的需求。我没有关注视觉方面,但强调元素的默认样式可能在不同浏览器之间不一致,因此请确保你提供合适的样式来配合它。

Web 存储可能不持久

WHATWG Web 存储规范包含一个关于隐私的部分,概述了防止存储成为跟踪向量的可能方法。其中一种方法是让数据过期。这就是 Safari 有争议地将脚本可写存储限制为七天的原因。请注意,这并不适用于添加到主屏幕的“已安装”网站。

结论

有趣吧?我们可能希望某些 Web 功能以某种方式工作,但事实并非如此。这并不意味着这些功能是错误的,需要修复,而更像是在我们编写代码时要提醒自己。

在开发过程中值得检查你自己的假设。批判性地检查你的用户需要什么,并在构建网站时将其考虑在内。当然,你可以在遇到这些问题时绕过它们,但在你无法绕过的情况下,请确保找到并提供合理的渐进增强和优雅降级。如果用户在每个浏览器中无法以完全相同的方式体验网站,只要他们能够完成他们需要做的事情,就可以了。

这是我不按预期工作的清单。你的清单上有什么?我确信你有一些,我很乐意在评论中看到它们!