封面图片:The AI Summary Said "It's Not a Scam." The Springboard Was Your Site's Search Box

Ken Imoto

去年八月,一名计划乘坐邮轮的男子在谷歌搜索皇家加勒比的客服电话。谷歌的 AI Overview 在搜索结果最上方提供了电话号码。他拨打了这个号码,并输入了信用卡信息,而这个号码其实属于诈骗分子。西南航空的搜索也出现了类似情况。这种变体——将虚假客服电话植入 AI 摘要可能抓取的位置——获得了大量报道。

上周,日本警视厅公布了一种更隐蔽的变体,我认为开发者应该更加关注,因为攻击面存在于合法网站上:搜索框。可能是你网站上的那个。

警方描述的情景是:有人在社交媒体上被邀请加入一个投资群组。在转账前,他做了明智的事——搜索了该群组的名称。结果显示“XX 不是骗局”和“我用 XX 赚到钱”。页面顶部的 AI 摘要也确认:“XX 不是骗局。”安心之后,他转了钱。

受害者的验证习惯——“让我先搜索再相信”——被纳入了陷阱。

读到这份报告时,我首先想到的是:这是怎么做到的?我日常从事 LLMO(优化网站以被 AI 搜索引用)工作,所以我怀疑这是 SEO 圈子中流传的搜索污染技术之一。线索指向了我预料之外、更古老且更愚蠢的东西:站点搜索垃圾信息,早在 2023 年 2 月就被日本 SEO 公司 JADE 记录。

本文将介绍其机制、为什么 AI 摘要会重复谎言,以及你本周就能部署的防御措施(noindex、X-Robots-Tag、零结果时返回 404)。

机制:三步,无需入侵

大多数带有搜索框的网站会通过类似 /search?q=keyword 的 URL 返回结果。典型实现有两个特性为攻击创造了条件:

  • 任何人都可以在查询参数中放入任意字符串
  • 页面会将该查询反映到其 <title><h1> 中(“搜索结果:'keyword' | Acme Corp”)

攻击流程:

  1. 攻击者在受信任域名上构建搜索 URL:acme.com/search?q=XX+is+not+a+scam。无需操作搜索框,URL 本身即可完成任务。
  2. 他们从自己控制的网站链接到该 URL。
  3. Googlebot 跟随链接,抓取结果页面并建立索引。从此,网页搜索即可在合法域名下显示“XX is not a scam | Acme Corp”。

受害网站从未被入侵。没有恶意软件、没有入侵、没有工具。攻击者只是构建了一个 URL 并放置了链接。当我第一次理解这一点时,我大声地说:“就这?”被利用的不是漏洞,而是规范。

对搜索者而言,看起来像是 Acme Corp 的网站在说“不是骗局”。域名多年来积累的信任被转租给了陌生人的句子。

为什么 AI 摘要会重复谎言

AI Overview 及类似功能在结构上接近 RAG:从搜索索引中检索与查询相关的页面,然后据此生成答案。内部机制不公开,但依赖关系是可观察的:摘要构建于索引的下游。

AI 无法察觉这种设置。它检索到的内容,在它看来是受信任域名上的文本。它不验证声明,只衡量来源权威性和跨来源一致性。因此,如果攻击者在多个知名域名的搜索 URL 中植入同一句子,AI 就会看到多个独立的权威来源达成一致。

丑陋之处在于:AI 对权威信号的权重越高,这种攻击就越有效。最勤勉的 AI 反而是最容易被欺骗的。

流程很简单:搜索索引在上游,AI 摘要在下游。污染上游,下游就会自我毒害。你可以等待 AI 厂商改善过滤(谷歌曾表示已对虚假电话号码“采取行动”,但新号码仍在不断出现),也可以在自己的网站上关闭反射面——这更快,而且完全在你掌控之中。

五分钟自检

你的网站是否可能被用作跳板?三项检查:

# 1. 你的搜索结果页面是否已被收录?(在 Google 中)
site:example.com inurl:search
site:example.com inurl:"?s="

# 2. 是否以可疑短语被收录?
site:example.com scam
site:example.com refund

进入全屏模式 退出全屏模式

# 3. 你的搜索结果页面是否带有 noindex?
curl -sI "https://example.com/search?q=test" | grep -i x-robots-tag

# 如果没有响应头?检查 HTML meta 标签
curl -s "https://example.com/search?q=test" | grep -i '<meta name="robots"'

进入全屏模式 退出全屏模式

site: 查询是快速的烟雾测试;Google 不保证结果完整。要获得确切答案,请打开 Search Console,检查“索引 > 页面”和“效果 > 页面”,查看包含 /search?s= 的 URL。

同时检查你的搜索结果模板:是否将查询反映到 <title><h1> 中?反射加上可索引性,正是让你成为目标的组合。

一点安慰:客户端搜索(浏览器中的 JS 过滤,静态网站常见)完全没有此攻击面,因为服务器不会根据查询返回不同的 HTML。

防御措施

基于 JADE 的建议,有两种可行策略:

措施 效果 注意事项
<meta name="robots" content="noindex"> 可靠地将结果页面排除在索引之外 若 robots.txt 屏蔽该页面则失效
X-Robots-Tag: noindex 响应头 相同效果,在基础设施层应用,无需修改模板 同上
零结果查询时返回 noindex(或 404) 保留搜索页 SEO 流量,同时阻挡垃圾信息 404 可能损害合法零结果查询的用户体验
robots.txt Disallow: /search 抑制抓取 单独使用不完整——被屏蔽的 URL 仍可能通过外部链接被索引

选择很简单:

  • 不追求搜索结果页的 SEO 流量?全部 noindex。最简单、最可靠。
  • 想保留该流量?在零结果查询时返回 noindex。像“XX is not a scam”这样的垃圾短语几乎总是零结果,因此单靠这一项就能阻止大部分攻击。

有一个陷阱值得铭记:noindex 只有在爬虫能读取页面时才有效。若用 robots.txt 屏蔽 URL,爬虫就看不到你的 noindex,整个防御就失效了。Google 的文档明确指出:要使 noindex 生效,页面不得被 robots.txt 屏蔽。切勿在同一 URL 上同时使用两者。

实现示例。

WordPress 搜索页面(?s=)若使用 Yoast 等插件,默认已带 noindex。在裸主题中,可使用 wp_robots 过滤器(WordPress 5.7+,与核心及插件输出兼容):

// functions.php
add_filter('wp_robots', function ($robots) {
    if (is_search()) {
        $robots['noindex'] = true;
    }    return $robots;
});

进入全屏模式 退出全屏模式

Next.js(App Router):

// app/search/page.tsx
export const metadata = {
  robots: { index: false, follow: true },
};

进入全屏模式 退出全屏模式

在基础设施层,使用 nginx。该代码片段有两个注意点:它匹配路径式搜索 URL(/search),而不匹配查询式(?s=);对于后者需改用 $arg_s 分支。另外,nginx 的 add_header 有继承规则:location 内的单个 add_header 会取消上层定义的所有响应头,因此需在此处重新声明安全响应头。

location /search {
    add_header X-Robots-Tag "noindex" always;
    # 在此处重新声明上层定义的 add_header 行(安全响应头等)
    proxy_pass http://app;
}

进入全屏模式 退出全屏模式

即使抛开诈骗角度,noindex 搜索结果页面也是标准的 SEO 卫生习惯:它能防止重复内容膨胀和抓取预算浪费。这是一个最终完成它的好借口。

总结

  • 日本警方警告的“不是骗局”污染,可用站点搜索垃圾信息来解释。被利用的是规范:反射查询、允许索引。
  • AI 摘要是基于搜索索引的 RAG。上游污染会变成下游答案。关闭你的反射面比等待 AI 端过滤更快。
  • noindex 是核心。永远不要对要 noindex 的 URL 使用 robots.txt 屏蔽。如需保留搜索流量,可在零结果时 noindex。

如果你运营网站,今天就试试 site:yourdomain inurl:search。如果有返回结果,上面的防御部分就是你下午的任务。你的搜索框是否正在承载别人的“不是骗局”?

参考资料