[译]只使用 CSS 进行用户追踪

在浏览器里进行用户追踪会引发关于隐私和数据保护一次又一次的讨论。类似 Google 分析之类的工具几乎可以抓到所有需要的内容,包括来源,语言,设备,停留时间等等。

但是,想获取一些感兴趣的信息,你可能不需要任何外部追踪器,甚至不需要 JavaScript。本文将向你展示,即便用户禁用了 JavaScript,依然可以跟踪用户的行为。

追踪器通常如何工作

通常,这类追踪器分析工具要使用到 JavaScript。因此,大多数等信息可以十分轻松的读取,并且可以立刻发送到服务端。

这就是为什么出现越来越多的方式来阻止浏览器中跟踪器的原因。。某些勇敢的浏览器或者某些 chrome 扩展程序会阻止跟踪器的加载,例如 google 分析。 其中一个诀窍是,例如 Google 分析总是从外部集成的,一段来自 Google CDN 的 JavaScript 代码。嵌入的 URL 总是相同的,因此可以轻松的将它阻止掉。

因此追踪器总是会用 JavaScript 做些什么。甚至如果你通过阻止 URL 限制了追踪器,网站拥有者可能会通过将 JavaScript 代码嵌入页面的方式继续使用。最强有力的保护措施就是禁用 JavaScript,虽然这可能会付出非常大的代价。

最后,我们仍然可以不使用 JavaScript 追踪一些内容,而是使用一些 CSS 技巧。当然 CSS 并不是为追踪使用的,让我们开始实践吧。

找到设备类型信息

媒体查询应该是每一个 web 开发者都知道的。有了这个,我们可以让 CSS 代码只在某些确定的屏幕条件下执行。所以我们可以为智能手机或平板电脑等,编写自己的查询条件。

我们所有 CSS 追踪器背后的魔法就是它们的属性,比如我们可以将一段 URL 作为属性值。有一个比较好的例子是 background-image 的属性,它允许我们为一个元素设置一张背景图片。这张图片从一段 URL 获取,并且在执行过程中,它是优先请求的,因此会向这个 URL 地址: background-image: url('/dog.png'); 发送一个 GET 请求。

但是最后,没人强制我们必须确保这段 URL 链接确实能访问到图片。服务器甚至不需要对请求进行应答,但我们仍然可以响应 GET 请求,向数据库输入数据。

const express = require("express");
const app = express();

app.get("/", (req, res) => {
  res.sendFile(__dirname + "/index.html");
});

app.get("/mobile", (req, res) => {
  console.log("is mobile")
  res.end()
)}

app.listen(8080)

至于后端,我使用 Express.js 作为服务器。它提供了一个简单的 HTML 网站;如果访问设备是智能手机,则会调用 mobile 路由。并且我们的后端是唯一使用 JavaScript 的地方。

@media only screen and (max-width: 768px) {
  body {
    background-image: url("http://localhost:8080/mobile");
  }
}

在我们的 index.html 文件中,我们有了上面的 CSS 代码。只有在用户设备与媒体查询匹配的时候,才请求背景图片。

如果现在一部智能手机访问这个页面,媒体查询会执行,并发送请求背景图片的请求,同时服务端会输出它是智能手机。这些操作是完全没有使用 JavaScript。

并且由于我们不会发送一张图片作为回应,这个网站内容将不会有任何改变。

找到操作系统信息

现在变得更加疯狂,我们能大致找到用户操作系统通过它支持的字体。在 CSS 中,我们可以使用多种后备方案,换句话说,可以指定多种字体。如果第一个在系统上不起作用,浏览器将会尝试第二个。

font-family: BlinkMacSystemFont, "Arial"; 当我在我们的网站嵌入这句代码时,我的 MacBook 使用第一种苹果标准字体,这字体只可以在 Mac OS 上使用。当在我的 Windows PC 上,Arial 正常使用。

当使用字体时,我们可以定义自定义字体以及从什么地方加载它。Google 字体的工作方式相同,如果我们要从某处使用自定义的字体,必须先从服务器加载它。并且我们可以多次使用字体。

 @font-face {
  font-family: Font2;
  src: url("http://localhost:8080/notmac");
 }

body {
  font-family: BlinkMacSystemFont, Font2, "Arial";
}

这里我们为了全部的 body 部分设置了字体。从逻辑上讲,你只能使用一种字体。以至于在 MacBook 上,使用的是第一种字体,即系统自己的字体。在类似 Windows 的其他系统上,系统检查字体是否存在。当然,肯定不存在,因此尝试使用下一种我们自己定义的字体。它仍然不得不从服务端加载,因此我们的 CSS 代码会再次触发 GET 请求。

毕竟 Font2 不是一个真正的字体,因此我们继续尝试,最终将使用 Arial 字体。尽管如此,我们仍然可以在用户无感知的情况下,使用一个合理的字体。

追踪元素信息

到目前为止,我们所做的事情就是当用户抵达网站,立即对信息进行分析。当然,我们也可以利用 CSS 对单独的事件做出应对。

如下所示,我们可以使用下面的例子,来分析鼠标悬停或活动事件。

<head>
  <style>
    #one:hover {
      background-image: url("http://localhost:8080/one-hovered/");
    }
  </style>
</head>
<body>
  <button id="one">Hover me</button>
</body>

当鼠标每次悬停在按钮上,它会一次又一次的设置背景图片,一个 GET 请求也随之发出。

我们可以在按钮被点击时,做相同的事情。在 CSS 中,这就是活动事件。

<head>
  <style>
    #one:active {
      background-image: url("http://localhost:8080/one-clicked/");
    }
  </style>
</head>
<body>
  <button id="one">Click me</button>
</body>

还有一系列其他事件。例如,悬停事件几乎适用在每一个元素上。因此从理论上来讲,我们可以追踪用户的每一个行为。

犹豫计时器

使用更多的代码,我们可以组合这些事件并且了解更多信息,而不仅仅是发生了那些事件。

对于许多网站主来说,更感兴趣的是,用户在看到或悬停在元素上犹豫了多久才点击某个元素。通过下面的代码,我们可以测量用户悬停后点击所花费的时间。

let counter;
app.get("/one-hovered", (req, res) => {
  counter = Date.now();
});

app.get("/one-active", (req, res) => {
  console.log("Clicked after", (Date.now() - counter) / 1000, "seconds");
});

用户一旦悬停,计时器就会启动。最后,我们可以算出直到点击过了几秒。

你可能会认为由于它嵌入在 CSS 代码中,统计的可能并不准确,但事实并非如此。由于请求的体积十分小,并且立即作用在服务器上。我试了几次并测量了时间,最终测量的结果非常精确。

很惊人,不是吗?

让整个功能更美观

为了不被发现,使用不显眼的 URL 是十分有意义的。 最后,每个人都可以看到完整的前端代码。

你也可以使用自己想到的关键词,代替个别特别显眼的路由单词。最后,前端和后端的 URL 必须匹配。

对于上面的示例,我始终将我自己的路由用作 GET 请求。这样十分清晰明白。一种更优雅的方式是使用 URL 的查询,这在 CSS 当中也适用。

@font-face {
  font-family: Font2;
  src: url("http://192.168.2.110:8080/os/mac");
  /* or: */ 
  src: url("http://192.168.2.110:8080/?os=mac");
}

有关 Express.js 中 URL 查询与参数的相关的详细教程可以在这里查看:

在 Express.js 中 URL 的查询与参数

如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

原文链接:juejin.im

上一篇:WebPack基础入门(一):万物皆可webpack
下一篇:Flutter——实现网易云音乐的滑动冲突处理效果

相关推荐

  • 😀一个原生js弹幕库,基于 CSS3 Animation

    BulletJs 😀一个原生js弹幕库,基于 CSS3 Animation 项目地址 演示图 2020-08-13更新 采用rollup打包并发布到npm,rollup打包教程...

    14 天前
  • 🔥 从最近流行的一幅 CSS 风景画中学习 2 个知识点

    最近 CodePen 流行的一张用纯 CSS 绘制的风景画令人印象深刻: 天空的眩光,睡眠反射,精细的房屋细节相当惊艳,下面我们大致说一说这张图片中的一些技术细节。图画的源码地址在文末。

    8 个月前
  • 💫 CSS 幻术 | 抗锯齿

    前言 传统网页的呈现是基于像素单位的,所以图片不能和 SVG 一样进行任意尺寸缩放后还保持边缘平整。也就是说,放大像素逻辑的图片,必然导致可视质量下降(信息失真)。

    6 个月前
  • 💖CSS + JS 送学妹满屏幕小爱心

    故事开始 午饭时间,暗恋已久的学妹拉着我的衣袖:“学长学长,你能不能让这些爱心变成五颜六色的吗~”。 我在旁边笑开了花~~~ 诶呀,口水流出来了。

    7 个月前
  • (译)CSS 定位与层叠上下文(Stacking context)

    你是否在使用定位时,会遇到一个定位元素即使设置更高的层级,也无法将另一个定位元素覆盖的情况?通过理解层叠上下文,你就能更好的构建你的应用。理解渲染流程和层叠顺序当浏览器将 HTML 解析成 DOM 结...

    2 个月前
  • 黑魔法之 CSS Entry

    大家都知道 webpack 的 Entry 都是 js,如果想输出 css 文件只能在 js 文件里导入 css,所以很多人都会想要是 entry 也可以是 css 那多好,这样就可以任意输出 cs...

    2 年前
  • 高度等于动态宽度(CSS流体布局)[复制品]

    web-tikiThomas Norman提出了一个问题:Height equal to dynamic width (CSS fluid layout) [duplicate],或许与您遇到的问题类...

    3 年前
  • 面试题CSS盒子模型,左右固定宽度,中间自适应的五种死法

    面试题目 假设高度已知,请写出三栏布局,左右300px,中间自适应 有几种方法呢? 最容易的应该想到利用float来写,代码如下 css样式代码,以下五种都是用一个样式代码 &lt;sectio...

    2 年前
  • 面试必备! CSS知识点总结

    一、 元素水平垂直居中的方法 水平居中 行内元素:text-align:center 已知元素的宽度 设置margin:0 auto 元素的宽度不确定 flex 布局 justify-...

    5 个月前
  • 面试官:谈谈你对 CSS 盒模型的认识?(你确定会?)

    题目:谈谈你对 CSS 盒模型的认识 涉及知识点(层层递进): 基本概念:标准模型+ IE模型(区别) CSS如何设置这两种模型 JS如何设置获取盒子模型对应的宽和高 实例题(根据盒模型解释边距...

    2 年前

官方社区

扫码加入 JavaScript 社区