Ad Tech

广告验证:使用HTTP代理检测伪装创意

4 min read Published Updated 832 words

广告验证已经失效。一份2023年的行业审计发现,通过主要交易平台投放的程序化广告展示中,有60-80%向验证机器人展示的创意与真实用户看到的不同。这就是广告伪装(cloaking)——它动摇了你读过的每一份品牌安全报告。解决方案是将验证爬虫视为攻击者:通过HTTP代理路由其流量,改变其指纹,并将渲染后的内容与已知安全的基线进行比较。

广告伪装如何选择目标

广告伪装依赖三个信号:User-AgentX-Forwarded-For(或直接IP)以及Referer。恶意广告服务器检查传入请求,判断访问者是验证机器人还是真实用户。机器人——例如来自Moat、Integral Ad Science或DoubleVerify的机器人——会发送可预测的标头。服务器随后向机器人提供干净、品牌安全的创意,而向其他所有人提供恶意或不恰当的创意。这种差异在验证者的仪表板上是不可见的。

实际案例包括仅向特定地理区域的移动用户展示成人内容、政治宣传或恶意软件重定向。攻击者检查User-Agent是否为“Mozilla/5.0 (Linux; Android …)”,并检查X-Forwarded-For是否属于已知验证供应商的IP范围。如果IP匹配,广告就是安全的。如果不匹配,用户就会收到有效载荷。

使用MITM代理检测差异

最可靠的检测方法是让您自己的验证爬虫通过透明HTTP代理——mitmproxyBurp Suite——运行,并将响应与未使用代理发送的控制请求进行比较。代理允许您捕获原始响应体并实时修改标头。您可以以不同的User-AgentX-Forwarded-For重放同一请求,观察广告服务器是否更改创意。

以下是一个最小的mitmproxy脚本,用于记录对同一URL使用不同用户代理的两个请求之间的差异:

# save as check_cloak.py
from mitmproxy import http

def request(flow: http.HTTPFlow) -> None:
    if "adserver.example.com" in flow.request.pretty_host:
        ua = flow.request.headers.get("User-Agent", "")
        if "Android" in ua:
            flow.request.headers["X-Forwarded-For"] = "1.2.3.4"  # bot IP
        else:
            flow.request.headers["X-Forwarded-For"] = "5.6.7.8"  # user IP

使用mitmproxy -s check_cloak.py --listen-port 8080运行它,然后将浏览器或curl指向该代理。比较响应体——如果HTML、图片或JavaScript不同,则说明存在伪装创意。

使用代理轮换进行地理定向爬取

广告伪装通常将GeoIP作为额外的区分因素。一个广告可能向来自美国的请求展示干净的创意,但对东南亚或东欧的用户则切换为恶意创意。要捕捉这一点,您必须从多个地理端点爬取同一广告URL。一组住宅代理(例如BrightData、Oxylabs)或SOCKS5代理链允许您同时设置X-Forwarded-For和TCP源IP。

使用带有代理和自定义标头的curl来模拟目标地区的移动用户:

curl -x socks5://user:pass@proxy-us-east:1080 \
  -H "User-Agent: Mozilla/5.0 (Linux; Android 13; Pixel 7)" \
  -H "X-Forwarded-For: 203.0.113.50" \
  -H "Referer: https://example.com/article" \
  -o response_us.html \
  https://adserver.example.com/ad

curl -x socks5://user:pass@proxy-vietnam:1080 \
  -H "User-Agent: Mozilla/5.0 (Linux; Android 13; Pixel 7)" \
  -H "X-Forwarded-For: 42.112.0.1" \
  -H "Referer: https://example.com/article" \
  -o response_vn.html \
  https://adserver.example.com/ad

对两个文件进行差异比较。<script>标签或图片src属性中的任何差异都表明存在基于地理位置的伪装。

移动端与桌面端创意的差异

广告伪装通常针对移动流量,因为移动用户不太可能检查网络请求。仅模拟桌面浏览器的验证爬虫会完全忽略这一点。您必须使用两种User-Agent字符串发送请求并比较响应。一种常见模式:桌面端响应包含标准的300x250横幅,而移动端响应则加载一个全屏插屏广告,重定向到钓鱼页面。

使用diffjq等工具比较JSON响应。对于HTML,使用htmlqpup提取特定元素。关键在于自动化跨用户代理、IP地理位置和引荐来源矩阵的比较。我构建的一个生产系统对每个广告单元运行16个并行请求,并标记任何超过5%字节大小阈值的变异。

权衡与局限性

这种方法并非完美。广告服务器可以检测代理IP范围,并向已知代理出口提供干净创意——就像它们检测验证机器人一样。轮换住宅代理有助于缓解问题,但会增加延迟和成本。此外,某些伪装是基于时间的:恶意创意仅在延迟后或JavaScript事件触发后才出现,而简单的curl请求无法触发这些事件。在这种情况下,您需要在代理后面使用无头浏览器(Puppeteer、Playwright),这会增加复杂性和可指纹性。

然而,核心原则依然成立:如果您无法在一组多样化的客户端指纹上重现完全相同的响应,那么该广告就不可信。HTTP代理让您能够以编程方式构建这些指纹。从一个简单的mitmproxy脚本和少量代理端点开始。仅此一项就能捕获大多数低成本的伪装活动——而且成本不过是几行Python代码。