苹果最新一支"Privacy on iPhone"广告把数据追踪者拍成了身着铬合金西装的人形影子——图书馆偷看肩头、通勤时趴在后背、深夜浏览时如影随形。"铬合金"(Chrome)的暗指毫不隐晦。广告主角用的是 Android 手机,追踪者寸步不离;切换到 iPhone 后,Safari 把这些"铬合金人"挡在了门外。
广告是营销,但背后的技术差异是真实的。Safari 的 Intelligent Tracking Prevention(ITP)和 Chrome 的隐私策略,在代码层面走的是两条路。
追踪者的"铬合金西装"到底是什么
广告里的"铬合金人"不是抽象比喻——它对应的是浏览器中真实存在的追踪链路:第三方 Cookie、指纹脚本、CNAME 伪装、跨站像素请求。一条典型追踪路径大致如下:
- 用户访问新闻站点 A,页面内嵌了广告平台的第三方脚本。
- 广告脚本通过第三方 Cookie 或 localStorage 写入唯一标识符。
- 用户随后访问购物站点 B,同一广告脚本再次加载,读取标识符,将两次访问关联到同一人。
- 用户画像越来越细:浏览了什么、停留多久、搜索了什么关键词、深夜几点还在刷手机。
广告中"图书馆偷看肩头"对应的是页面内的行为追踪(滚动深度、点击热区);"通勤趴后背"对应的是跨站关联;"深夜如影随形"对应的是持续性的 Cookie 跟随。每一步都有具体的 JavaScript API 在执行。
Safari ITP 与 Chrome 的技术分岔
Safari 从 2017 年起逐步推进 ITP,核心逻辑是按行为分类、按分类限制,而不是一刀切:
| 追踪类别 | Safari ITP 处置 | Chrome 当前处置 |
|---|---|---|
| 第三方 Cookie | 默认阻止,仅允许 24 小时窗口后降级为分区 Cookie | 2024 年逐步限制第三方 Cookie,但延迟多次,目前仍可通过 Privacy Sandbox API 替代 |
| CNAME 伪装追踪 | 检测第一方子域请求中的追踪模式,7 天滚动窗口后阻断 | 不做 CNAME 层面特殊检测 |
| localStorage / IndexedDB | 对被分类为追踪域的存储,7 天后清除 | 无类似时间窗口清除机制 |
| 指纹防御 | 默认冻结 canvas/WebGL/音频指纹 API 的可区分信息 | 需手动开启 Strict mode 或依赖扩展 |
| 跨站导航追踪 | 检测 referrer 裁剪、链接装饰参数,自动剥离 | 部分 referrer 策略限制,但不主动剥离追踪参数 |
关键区别在于主动性:Safari 用机器学习模型分类追踪域,然后自动施加限制,用户不需要配置任何东西;Chrome 的策略更多依赖站点自愿迁移到 Privacy Sandbox API(如 Topics、Attribution Reporting),而旧式追踪在过渡期内仍可运作。
广告里 Android 用户被"铬合金人"缠住、iPhone 用户甩掉它们——这个画面对应的就是:一个浏览器默认放行追踪然后逐步收紧,另一个默认阻断追踪然后按需放行。
自己动手:审计任意网页的追踪脚本
广告是感性冲击,但作为开发者,你可以用工具量化追踪的真实规模。下面是一个可直接运行的 Python 脚本,抓取任意网页,分析其中嵌入的第三方脚本域名和 Cookie 设置情况:
"""
audit_trackers.py — 审计网页中的第三方追踪脚本与 Cookie
用法: python audit_trackers.py <url>
依赖: pip install requests beautifulsoup4
"""
import sys
import re
from urllib.parse import urlparse
from collections import Counter
import requests
from bs4 import BeautifulSoup
# 已知追踪/广告域名片段(可自行扩展)
TRACKER_KEYWORDS = [
"doubleclick", "googlesyndication", "google-analytics",
"googletagmanager", "facebook", "fbcdn", "meta",
"adservice", "adnxs", "amazon-adsystem", "criteo",
"taboola", "outbrain", "hotjar", "clarity",
"segment", "amplitude", "mixpanel", "quantserve",
"scorecardresearch", "moatads", "rubiconproject",
]
def is_tracker(domain: str) -> bool:
return any(kw in domain.lower() for kw in TRACKER_KEYWORDS)
def audit(url: str):
# 发起请求,保留 Cookie
session = requests.Session()
resp = session.get(url, timeout=15, headers={
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
"AppleWebKit/605.1.15 (KHTML, like Gecko) "
"Version/18.1 Safari/605.1.15"
})
page_domain = urlparse(url).netloc
soup = BeautifulSoup(resp.text, "html.parser")
# 收集所有 <script src=...> 的域名
script_domains = []
for tag in soup.find_all("script", src=True):
d = urlparse(tag["src"]).netloc
if d and d != page_domain:
script_domains.append(d)
# 收集 <img> 像素追踪(1x1 或无尺寸的第三方图片)
pixel_domains = []
for tag in soup.find_all("img", src=True):
d = urlparse(tag["src"]).netloc
w = tag.get("width", "")
h = tag.get("height", "")
if d and d != page_domain and (str(w) in ("1", "") or str(h) in ("1", "")):
pixel_domains.append(d)
# 收集 <link rel=preconnect> 的域名(预连接暗示频繁第三方请求)
preconnect_domains = []
for tag in soup.find_all("link", rel="preconnect"):
href = tag.get("href", "")
if href:
preconnect_domains.append(urlparse(href).netloc)
# 分析 Cookie
cookies = session.cookies.get_dict()
third_party_cookies = {
k: v for k, v in cookies.items()
if any(is_tracker(d) for d in script_domains)
}
# 输出报告
tracker_scripts = [d for d in script_domains if is_tracker(d)]
non_tracker_3rd = [d for d in script_domains if not is_tracker(d) and d != page_domain]
print(f"=== 追踪审计报告: {url} ===")
print(f"页面域名: {page_domain}")
print(f"第三方脚本总数: {len(script_domains)}")
print(f" 已识别追踪脚本: {len(tracker_scripts)}")
for d, cnt in Counter(tracker_scripts).most_common():
print(f" - {d} (出现 {cnt} 次)")
print(f" 其他第三方脚本: {len(non_tracker_3rd)}")
for d, cnt in Counter(non_tracker_3rd).most_common():
print(f" - {d} (出现 {cnt} 次)")
print(f"像素追踪请求: {len(pixel_domains)}")
for d in pixel_domains:
print(f" - {d}")
print(f"预连接域名: {len(preconnect_domains)}")
for d in preconnect_domains:
marker = " ⚠️ 追踪域" if is_tracker(d) else ""
print(f" - {d}{marker}")
print(f"会话 Cookie 总数: {len(cookies)}")
print(f"疑似追踪相关 Cookie: {len(third_party_cookies)}")
for k, v in third_party_cookies.items():
print(f" - {k} = {v[:40]}...")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("用法: python audit_trackers.py <url>")
sys.exit(1)
audit(sys.argv[1])
运行示例:
pip install requests beautifulsoup4
python audit_trackers.py https://www.example-news-site.com
你会看到大多数新闻和电商网站加载了 10-30 个第三方脚本,其中一半以上属于已知追踪域。换用 Safari 打开同一页面时,ITP 会在 24 小时后阻断这些域的 Cookie 读写——这就是广告里"铬合金人"被挡在门外的技术实现。
如果你想在浏览器里实时观察,Safari 的 Web Inspector(开发者工具 → 网络 → 筛选第三方请求)和 Chrome 的 chrome://settings/privacy 面板都能看到被阻断的 Cookie 数量差异。
选择浏览器的隐私代价清单
广告用情绪驱动认知,但日常选择是工程决策。以下是实际取舍:
如果你优先隐私:
- ✅ Safari ITP 默认阻断第三方追踪,无需配置
- ✅ Safari 指纹防御默认开启,canvas/WebGL 返回冻结值
- ⚠️ 部分网站登录态可能 7 天后失效(ITP 对 CNAME 追踪域的存储清除)
- ⚠️ Safari 扩展生态小于 Chrome,某些开发工具不可用
如果你优先兼容与生态:
- ✅ Chrome 扩展生态完整,DevTools 功能更丰富
- ✅ Privacy Sandbox API(Topics 等)正在推进,但站点迁移进度缓慢
- ⚠️ 第三方 Cookie 完全阻断的时间线已多次推迟(当前目标 2025 年仍不确定)
- ⚠️ 指纹防御需手动开启 Strict mode 或依赖扩展
通用加固操作(任何浏览器都应做):
- 关闭浏览器内置的"增强广告隐私"或"广告个性化"选项——这些选项本身就是追踪的数据源。
- 安装 uBlock Origin 或 AdGuard,拦截已知追踪脚本网络请求。
- 定期清除 localStorage 和 Cookie,或使用隐私窗口处理敏感浏览。
- 检查浏览器是否发送
Do-Not-Track或GPC(Global Privacy Control)信号——Safari 默认发送 GPC,Chrome 不发送。
广告里的"铬合金人"是夸张的视觉修辞,但追踪脚本的数量是可量化的。跑一遍上面的审计脚本,看看你日常访问的网站加载了多少第三方域——数字本身就是最好的说服力。