守护我的Git Forge免受AI抓取器侵扰

单个仓库可抓取的页面总量为3240亿2260万808千132页。

 💬 123 条评论 |  爬虫 | 

目录
元素周期表

保护我的Git代码库所采用的技术概要


2024年8月,我的室友兼合伙人向公寓群聊发消息称,她发现我们住处的网络又变慢了,而且我的代码仓库所有页面加载时间都超过15秒。

我本以为这只是个小问题,便着手排查。然而很快,我便发现每天有数千个独立IP地址发起数十万次请求,持续不断地抓取我代码仓库中看似随机的页面。

本文总结了因大量爬虫试图下载我代码仓库数百万提交记录而引发的实际问题,以及我采取的限制损害措施。

# 为何创建代码仓库?§

2025年的网络世界里,万物皆可被抓取。人类思想孕育的一切成果,都可能沦为史上最大规模劳动窃取计划的猎物。本文在任何可索引页面发布的那一刻,便会被纳入无数用于训练基础大型语言模型的数据集。我的文字、你的文字,都在推动支撑着最大规模、最畸形财富积累的神经网络权重发生微小变化——这种财富积累的规模,远超我父母、祖父母乃至曾祖父母有生之年所见。

对了,代码库的提交记录可不少。试想:若你拥有公开暴露的代码仓库,每个文件夹中每次提交的所有文件都将相互关联。若再叠加其他操作——比如对单个文件执行git blame追溯——则需乘以文件数与提交数。原始下载链接同样需乘以提交次数。

假设你有一个Linux仓库,仅包含master分支截至2025年9月18日v6.17标签的所有提交。这意味着在1da177e4c3f4..e5f0a698b34e范围内的1,383,738次提交。这包含多少个文件?答案如下:

count=0;
while read -r rev; do
    point=$(git ls-tree -tr $rev | wc -l);
    count=$(( $count + $point ));
    printf "[%s] %s: %d (tot: %d)\n" $(git log -1 --pretty=tformat:%cs $rev) $rev $point $count;
done < <(git rev-list "1da177e4c3f4..e5f0a698b34e");
printf "Total: $count\n";

我对v6.17之前的100个提交运行了此命令。使用git ls-tree -tr $rev可统计文件和目录总数,若改用git ls-tree -r $rev则仅显示文件。我得到的结果是:72024729个文件,以及76798658个文件和目录。若对Linux主分支的完整历史记录运行该命令,则得到78,483,866,182个文件,以及83,627,462,277个文件和目录。

现在,若要估算拥有Linux副本时可抓取的页面数量,可应用以下公式:

(Ncommits * Nfiles) * 2 + (Ncommits * Nfilesandfolders) * 2 + Ncommits * 3

即应用于我的假想Linux仓库:

78483866182 * 2 + 83627462277 * 2 + 1383738 * 3 = 324,226,808,132 pages

其中*3项考虑了每个提交的每个文件均可原始抓取并执行git-blame分析。公式第二部分计入所有文件/目录页面,第三部分计入每个提交文件与历次版本的理论可比对操作,最后一项则计入所有提交摘要页面。

由此得出,单个仓库可抓取的页面总量为3240亿2260万808千132页。假设每个进入仓库的抓取程序会记录页面上所有其他链接,并上报给其他程序进行抓取。这些抓取程序实质上如同2000年代初爬行互联网建立索引的网络蜘蛛,区别在于它们无视robots.txt文件,且会持续不断地抓取新链接——完全不考虑如何降低对您(作为主机方)的成本负担。

# 抓取的代价§

撰写本节初稿时,我已移除此前实施的长期防护措施,以便收集最新数据展示问题的严重性。

我为Git Forge的电力开支买单。好吧,实际上是室友之一支付的,但我们将其记在费用分摊表里(当我们记得记录时)。

当初我开始对抗爬虫时,我的Git代码库托管在客厅里一台老旧的台式机上。如今它已迁移至家中机架式服务器的虚拟机中。虽然没能测量台式机被抓取与否的功耗差异,但机架服务器数据清晰可查。记忆所及,遏制抓取浪潮后,服务器功耗从约170瓦降至约150瓦。

目前该服务器所有硬盘持续运转且所有保护机制关闭时,持续从电网消耗200W电力。实验结束时,我和室友计算出抓取行为导致的能耗差异每年约耗费60欧元。

另一项相关成本是:运行代码库的虚拟机正因海量查询请求而面临“窒息”状态。不同类型的查询消耗也存在差异:查看文件blame记录或提交间diff差异的请求,其资源消耗远高于渲染仓库首页。上次大规模抓取导致我的虚拟机出现4个CPU核心99%以上负载及2.5GiB内存占用,而我通常观察到的使用率接近4%的CPU占用,内存波动在1.5GiB至2GiB之间。

此刻撰写本文时,运行forgejo的虚拟机正吞噬着8个CPU核心的100%资源。

此外,网络开销同样显著。各类监控工具让我能实时查看公寓内的流量统计。在实施首批反爬措施前,我们能清晰看到运行锻造站的台式机持续向互联网发送流量。室友们抱怨网络变慢的抱怨并非空穴来风:当多人同时观看直播或进行大文件下载时,锻造站外发流量会导致网络被限速。[1]

我的代码仓库虚拟机持续输出至少4MBps(32Mbps)的数据流量。

最后是人力成本:我曾连续整整数日守在终端前,试图搞清楚1)到底发生了什么鬼事,以及2)该如何解决这鬼事。我曾与其他自建基础设施的同行交流,拼命寻找既能解决问题又不影响用户的可行方案。最讽刺的是:那台Rackable服务器就摆在客厅里,正对着我的卧室门。它平时像可爱的小猫般轻声运转,但最近嗡鸣声越来越响——我能听见它。就在我试图入睡时

# 来做些统计吧。§

我好奇地分析了nginx日志,想弄清楚流量来源及其分布形态。

作为研究案例,我们可以分析/var/log/nginx/git.vulpinecitrus.info/目录中2025-11-142025-11-19期间的日志。需注意:在2025-11-1518:27 UTC时,我停止了将新代理重定向至Iocaine爬虫迷宫的操作(详见下文)。随后于19:15 UTC移除了/Lymkwi/linux/路径的nginx请求限制区域。于19:16 UTC取消了对标记为机器人IP与非机器人IP日志文件的分离存储。

后续逐步实施的三项措施为:启用网页缓存(2025-11-17)、手动将IP发送至带速率限制的垃圾生成器 (Iocaine 2) (2025-11-14, 15 和 18),以及 Iocaine 3 (2025-11-19)。

Common Logs Successful Delayed (429) Error (5XX) Measures in place
2025-11-14 275323 66517 0 Iocaine 2.1 + Rate-limiting
2025-11-15 71712 54259 9802 Iocaine 2.1 + Rate-limiting
2025-11-16 140713 0 65763 None
2025-11-17 514309 25986 3012 Caching, eventually rate-limiting2
2025-11-18 335266 20280 1 Iocaine 2.1 + Rate-limiting
2025-11-19 3183 0 0 Iocaine 3
Bot Logs Successful Delayed (429) Error (5XX) Measures in place
2025-11-14 (bots) 41388 65517 0 Iocaine 2.1 + Rate-limiting
2025-11-15 (bots) 34190 53403 63 Iocaine 2.1 + Rate-limiting
2025-11-16 (bots) (no bot-specific logs)
2025-11-17 (bots) (no bot-specific logs)
2025-11-18 (bots) 390013 0 13 Iocaine 2.1 + Rate-limiting
2025-11-19 (bots) 731593 0 0 Iocaine 3

表1:每日查询次数统计

(生成表1所用命令)

假设日志文件名为git-access-2025-11-14.log.gz

zcat git-access-2025-11-14.log.gz | grep '" 200 ' | wc -l
zcat git-access-2025-11-14.log.gz | grep '" 429 ' | wc -l

简而言之,缓存机制彻底失败。仅对Linux仓库实施手动速率限制(针对华为云和阿里云IP)虽有改善,但效果有限。当所有防护措施失效时,服务器响应严重迟滞,导致后端错误(通常为超时)激增。缓存过程中也出现故障——nginx在缓冲响应时遭遇异常。总体而言,缓存反而刺激了更多查询请求。

部署Iocaine后,绝大多数请求被成功分流至后端之外,未出现任何错误报告,也未产生延迟——因为所有我手动限流的IP地址均被Iocaine拦截处理。

在所有请求中,117.64.70.34是来源最频繁的IP,共计226023次请求来自中国网骨干网ASN(AS4134)。其次是136.243.228.193(13849次查询),该IP属于Hetzner公司,其主机名讽刺地解析为crawling-gateway-136-243-228-193.dataforseo.com。第三位是172.17.0.3(6908次查询),该IP属于VC Status的运行状态检测器;第四位是74.7.227.127(6117次查询),该IP来自微软AS 8075。

Day Unique IP Count
2025-11-14 16461
2025-11-15 18639
2025-11-16 41712
2025-11-17 47252
2025-11-18 22480
2025-11-19 14230

表2:查询Forge的唯一IP总数统计

(生成表2所用命令)

假设您的日志文件名为 *git-access-2025-11-14.log.gz

zcat \*git-access-2025-11-14.log.gz | awk '{ print $1 }' | sort | uniq -c | wc -l

在限制解除或仅缓存的两天里,查询代码库的独立IP数量翻倍。你越是便利这些爬虫的工作,它们就越会猛烈冲击你的系统。它们永远试图从你的服务器获取超出你承载能力的信息。

Day Top 1 Top 2 Top 3 Top 4 Top 5
2025-11-14 (226089) – /reibooru/reibooru (40189) – /Lymkwi/linux (1454) – / (1405) – /rail (1174) – /Soblow/indi-hugo
2025-11-15 (35163) – /Lymkwi/linux (18952) – /vc-archival/youtube-dl (4197) – /vc-archival/youtube-dl-original (1655) – /reibooru/reibooru (1635) – /Lymkwi/gr-gsm
2025-11-14 (bots) (40189) – /Lymkwi/linux (270) – /oror/necro (79) – /Lymkwi/[REDACTED]3 (55) – /vc-archival/youtube-dl (52) – /oror/asm
2025-11-15 (bots) (32895) – /Lymkwi/linux (260) – /oror/necro (193) – /Lymkwi/gr-gsm (95) – /Lymkwi/[REDACTED]3 (48) – /alopexlemoni/GenderDysphoria.fyi
2025-11-16 (72687) – /vc-archival/youtube-dl (23028) – /Lymkwi/linux (16779) – /vc-archival/youtube-dl-original (5390) – /reibooru/reibooru (3585) – /Lymkwi/gr-gsm
2025-11-17 (361632) – /vc-archival/youtube-dl (74048) – /vc-archival/youtube-dl-original (18136) – /reibooru/reibooru (13147) – /oror/necro (12921) – /alopexlemoni/GenderDysphoria.fyi
2025-11-18 (227019) – /vc-archival/youtube-dl (46004) – /vc-archival/youtube-dl-original (12644) – /alopexlemoni/GenderDysphoria.fyi (12624) – /reibooru/reibooru (7712) – /oror/necro
2025-11-18 (bots) (261346) – /vc-archival/youtube-dl (43923) – /vc-archival/youtube-dl-original (20195) – /alopexlemoni/GenderDysphoria.fyi (18808) – /reibooru/reibooru (10134) – /oror/necro
2025-11-19 (1418) – / (1248) – /rail (356) – /Soblow (31) – /assets/img (25) – /Soblow/IndigoDen
2025-11-19 (bots) (448626) – /vc-archival/youtube-dl (73164) – /vc-archival/youtube-dl-original (39107) – /reibooru/reibooru (37107) – /alopexlemoni/GenderDysphoria.fyi (25921) – /vc-archival/YSLua

表3:每日成功访问量前五的仓库/账户/页面

(生成表3的命令)

假设您需要名为git-access-2025-11-14.log.gz的日志文件数据:

 zcat git-access-2025-11-14.log.gz | grep '" 200 ' | awk '{ print $7 }' \
    | cut -d/ -f -3 | sort | uniq -c | sort -n \
    | tail -n 5 | tac

大型仓库因其海量提交记录和文件数量,成为爬虫的丰饶资源。一旦爬虫进入这类仓库,便会耗费极长时间才能离开——至少由于仓库内部链接可生成的页面数量极其庞大。

绝大多数合法流量似乎都集中在两种场景:获取个人资料(部分用户在联邦宇宙个人简介中列出了资料链接)或访问我的代码库平台根页面。

2025-11-14 (all) 2025-11-15 (all) 2025-11-16 (all)
Top 1 (8532) – AS136907 (Huawei Clouds) (8537) – AS136907 (Huawei Clouds) (8535) – AS136907 (Huawei Clouds)
Top 2 (2142) – AS45899 (VNPT Corp) (2107) – AS45899 (VNPT Corp) (4002) – AS212238 (Datacamp Limited)
Top 3 (803) – AS153671 (Liasail Global Hongkong Limited) (895) – AS153671 (Liasail Global Hongkong Limited) (3504) – AS9009 (M247 Europe SRL)
Top 4 (555) – AS5065 (Bunny Communications) (765) – AS45102 (Alibaba US Technology Co., Ltd.) (3206) – AS3257 (GTT Communications)
Top 5 (390) – AS21859 (Zenlayer Inc) (629) – AS5065 (Bunny Communications) (2874) – AS45899 (VNPT Corp)

(79) – /Lymkwi/[REDACTED][2]

表4:前三天每日顶级ASN统计(按唯一IP计数)

(生成表4所用命令)

为此我需要IP到ASN的映射数据库。通过在IPInfo注册免费账户并调用其Web API获取该数据库。我首先编写脚本实现唯一IP地址到AS号的映射。例如针对日志文件bot-git-access-2025-11-18.log.gz

while read ip; do
    ASN=$(curl -qfL api.ipinfo.io/lite/$ip?token=<my token> | jq -r .asn);
    printf "$ip $ASN\n" | tee -a 2025-11-18-bot.ips.txt;
done < <(zcat bot-git-access-2025-11-18.log.gz | awk '{ print $1 }' | sort | uniq)

随后基于此映射运行:

cat 2025-11-18-bot.ips.txt | cut -d' ' -f 2 | sort | uniq -c | sort -n | tail -n 5

访问量最大的来源依次为:华为云(VPS服务商)、VPNT(越南移动及家庭网络服务商)、Liasail Global HK Limited(VPS/AI赋能服务商)、Bunny Communications LLC(住宅宽带服务商)以及Zenlayer(CDN/云基础设施服务商)。当我解除所有防护措施后,Datacamp Limited(VPS服务商)、GTT Communications(据我所知实为骨干运营商的某家看起来像垃圾的ISP[3])以及M247 Europe SRL(托管服务商)突然出现在统计中。若记忆无误,Datacamp、GTT和M247正是我在2024年夏季初始调查中标记过的公司,当时已将其与华为云、阿里巴巴等全部纳入手动封禁/限流IP列表。

有趣的是,Liasail和Zenlayer的首页都标榜“赋能AI”。确实如此。令人担忧的是,VNPT和Bunny Communications属于家庭/移动ISP。虽然无法确定其IP是否来自国内用户,但当排除最明显的恶意行为者后,这些公司竟位列主要抓取来源之列,着实令人忧心。

# 防护措施§

我只有一个目标和一个限制条件。目标是尽可能保护代码库,手段包括阻断机器人或将成本转嫁给VPS服务商(其电费由我承担)。唯一限制:我拒绝部署基于工作量证明的验证码系统,例如Anubis。这些限制源于两点考量:

  1. 我个人认为强迫访客消耗更多计算资源来证明其非爬虫的行为实属不良实践。现实中存在合法需要访问权限却受限于计算能力或功能的设备。当然,确实存在多种验证方案,其中部分方案考虑了低功耗设备甚至无法运行JavaScript的设备,但
  2. 爬虫能轻易绕过Anubis。这并非设计缺陷。Anubis是危害减缓机制,而非万能灵药。

我尝试过多层解决方案:

  • 在反向代理端缓存
  • 使用无分类器的Iocaine 2,使其对任何查询都返回垃圾响应
  • 手动重定向IP并实施速率限制
  • 部署带分类器的Iocaine 3(Nam-Shub-of-Enki)

## 反向代理缓存§

我必须坦白:我从未意识到 nginx 默认不进行任何缓存。这个发现随即伴随着另一个认知——正确实现缓存非常困难。或许某天我会写下保护某项服务的经历,该服务会在联邦宇宙中发布指向自身的链接,而我的方案能避免每次发布后服务卡顿十分钟。

至于后续内容,我将展示基于nginx的解决方案。但请放心,任何优秀的反向代理软件都能实现完全相同的效果。

为我的代码仓库创建缓存时,我在/etc/nginx.conf中添加了以下配置:

proxy_cache_path /var/cache/nginx/forge/ levels=1:2 keys_zone=forgecache:100m;

这将创建名为forgecache的两级缓存,用于存储位于/var/cache/nginx/forge目录下的100MB数据。我创建该目录并将其所有者和组设置为www-data

在存放Git代码库站点配置的/etc/nginx/sites-enabled/vcinfo-git.conf文件中,我修改了负责服务根目录的location块:

location / {
    proxy_cache forgecache;
    proxy_buffering on;
    proxy_cache_valid any 1h;
    add_header X-Cached $upstream_cache_status;
    expires 1h;
    proxy_ignore_headers "Set-Cookie";
    proxy_hide_header "Set-Cookie";

    # more stuff...
}

该配置实现以下功能:在代理层启用缓存与缓冲(通过proxy_buffering指令,详见[https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering]),指定使用forgecache缓存(通过proxy_cache指令,详见[https://nginx.org/en/docs/ http/ngx_http_proxy_module.html#proxy_cache)),并将页面有效期设为一小时(proxy_cache_valid)。同时添加了一个用于调试缓存命中/未命中的cookie(add_header)。expires指令会向访客浏览器发送过期标记,告知其缓存内容同样在一小时后失效(参见expires说明:https://nginx.org/en/docs/http/ngx_http_headers_module.html#expires)。最后,缓存机制会忽略所有设置Cookie的响应头(proxy_ignore_headers proxy_hide_header),试图移除用户登录后可能被个性化的页面。

结果如何?缓存成了灾难,这完全在意料之中。缓存机制适用于重复调用相同资源的情境,例如页面素材、JavaScript、样式表等。而本次数千个查询我锻造平台的参与者经过某种协调机制,几乎不会重复调用相同资源,仅下载网页的原始HTML代码。

更糟的是,缓存破坏了认证页面的显示。上述代码片段不足以区分认证会话与未认证会话,导致我的锻造系统严重崩溃。我不得不提前在2025-11-17禁用缓存并启用下一层防护,否则根本无法使用该系统。

## 代理层速率限制§

后续防护层仅需对访问量最高的仓库启用全局速率限制:

limit_req_zone wholeforge zone=wholeforge:10m rate=3r/s;

server {
    // ...
	location ^~ (/alopexlemoni/GenderDysphoria.fyi|/oror/necro|/Lymkwi/linux|/vc-archival/youtube-dl-original|/reibooru/reibooru) {
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_max_temp_file_size 2048m;

		limit_req zone=wholeforge nodelay;

		proxy_pass http://<my actual upstream>/;
	}
}

通过两条指令实现:首条指令limit_req_zone置于server {}块外,定义名为wholeforge的区域,该区域存储10MB状态数据并限制每秒3次请求。

然而配置完成后,普通用户访问Linux仓库(或任何高频访问仓库)时,却陷入等待与请求超时的噩梦。

## 手动重定向至垃圾生成器§

由于缓存(可预见地)毫无用处,速率限制也阻碍了我的工作,我重新启用了实验前的初始设置:手动将查询重定向至垃圾生成器(此处采用旧版Iocaine)。该方案主要基于我最初遵循法语教程的配置。

本部分无需了解Iocaine的具体功能。下一节将展示我当前的最终配置方案,其中更新版的Iocaine已集成分类器,可区分机器人与普通用户请求。现阶段仅介绍基于IP地址手动筛选垃圾请求的版本。

作为额外功能,该方案还将对这些垃圾数据饥渴的机器人实施速率限制。

我在/etc/nginx/snippets/block_bots.conf文件中添加以下内容:

if ($bot_user_agent) {
    rewrite ^ /deflagration$request_uri;
}
if ($bot_ip) {
    rewrite ^ /deflagration$request_uri;
}
location /deflagration {
    limit_req zone=bots nodelay;
    proxy_set_header Host $host;
    proxy_pass <garbage upstream>;
}

该配置将强制所有被归类为bot_user_agentbot_ip的请求转发至提供垃圾内容的上游服务器。该上游服务器同时受到名为bots的区域速率限制保护,具体规则将在后续代码中定义。此配置片段需通过include指令嵌入server {}块中。

随后在 /etc/nginx/conf.d/bots.conf 中添加:

map $http_user_agent $bot_user_agent {
    default 0;

    # from https://github.com/ai-robots-txt/ai.robots.txt/blob/main/robots.txt
    ~*amazonbot 1;
    ~*anthropic-ai  1;
    ~*applebot  1;
    ~*applebot-extended 1;
    ~*brightbot 1;
    ~*bytespider  1;
    ~*ccbot 1;
    ~*chatgpt-user  1;
    ~*claude-web  1;
    ~*claudebot 1;
    ~*cohere-ai 1;
    ~*cohere-training-data-crawler  1;
    ~*crawlspace  1;
    ~*diffbot 1;
    ~*duckassistbot 1;
    ~*facebookbot 1;
    ~*friendlycrawler 1;
    ~*google-extended 1;
    ~*googleother 1;
    ~*googleother-image 1;
    ~*googleother-video 1;
    ~*gptbot  1;
    ~*iaskspider  1;
    ~*icc-crawler 1;
    ~*imagesiftbot  1;
    ~*img2dataset 1;
    ~*isscyberriskcrawler 1;
    ~*kangaroo  1;
    ~*meta-externalagent  1;
    ~*meta-externalfetcher  1;
    ~*oai-searchbot 1;
    ~*omgili  1;
    ~*omgilibot 1;
    ~*pangubot  1;
    ~*perplexitybot 1;
    ~*petalbot  1;
    ~*scrapy  1;
    ~*semrushbot-ocob 1;
    ~*semrushbot-swa  1;
    ~*sidetrade 1;
    ~*timpibot  1;
    ~*velenpublicwebcrawler 1;
    ~*webzio-extended 1;
    ~*youbot  1;

    # Add whatever other pattern you want down here
}

geo $bot_ip {
    default 0;

    # Add your IP ranges here
}

# Rate-limiting setup for bots
limit_req_zone bots zone=bots:30m rate=1r/s;

# Return 429 (Too Many Requests) to slow them down
limit_req_status 429;

该配置实现两项映射:客户端IP与变量bot_ip的关联,以及客户端用户代理与变量bot_user_agent的关联。当检测到上述区块中列出的已知模式时,对应变量将翻转为预设值(此处为1)。否则该变量保持0。接着定义速率限制区域,用于减缓机器人访问速度以防止其过快消耗资源。此时需安装http-geoip2 Nginx模块(在Debian系发行版中,执行apt install libnginx-mod-http-geoip2即可)。

完成上述操作后,在需要保护的每个站点的server块中添加以下行:

include /etc/nginx/snippets/block_bots.conf;

当您足够自信时,执行nginx -t命令并重新加载nginx单元。

若您使用的是caddy或其他反向代理,通常也提供类似的配置机制。你可以查阅Iocaine的文档,或在线搜索具体教程——相信其他人制作的教程会比我更完善。

启用该功能后,我立即将阿里云和华为云的所有IP地址加入机器人配置文件,服务器活动随即减缓。功耗降至约180W,CPU使用率降至60%左右,刺耳噪音也消失了。

然而如先前统计所示,仍有大量流量直击服务器本身。更诡异的是每隔三小时仍会出现持续约一个半小时的流量峰值,期间服务器再度发出嗡鸣声,forgejo 程序几乎窒息。

机器人仍在攻击我的服务器,且没有明确的来源。

## 自动分类机器人并毒害它们: Iocaine与Nam-Shub-of-Enki§

目前展示的步骤适用于单个IP持续攻击锻造服务器,或某人从你无意阻断的自治系统中明显抓取数据的情况。遗憾的是,如上文表4所示,大量抓取行为竟源自宽带地址。我虽能构建任意规模的IP黑名单或封禁整个ASN,但更渴望实现按查询判断合法性的机制。

下一阶段的防护将基于用户代理可信度对源IP进行分类。该机制主要参照Iocaine 3.x文档设计。终于要谈到Iocaine了!

Iocaine是一款将爬虫困于无意义页面迷宫的工具,这些页面会无限循环跳转至更多无意义页面。其内容通过马尔可夫链生成,基于软件接收的文本语料库。Iocaine(至少指3.0及以上版本[4])作为中间件运行,部署于反向代理与服务端之间。反向代理首先将流量重定向至Iocaine,若Iocaine判定请求有效,则向反向代理返回421 请求误导状态码。此时反向代理需捕获该响应,并切换至真实上游作为备用方案。若Iocaine的Nam-Shub-of-Enki[5]判定请求源自虚假或不良来源,它将欣然返回200 OK并发送生成的垃圾数据。

我的配置将 Iocaine 3 部署在 nginx 与开发环境之间,遵循Iocaine 文档使用容器版本。建议您依此操作,并添加以下设置以启用分类统计功能,同时防止其依赖的日志占满存储空间:

  1. etc/config.d/03-nam-shub-of-enki.kdl 中,将日志配置块修改为:
logging {
    enable #true
    classification {
        enable #true
    }
}
  1. docker-compose.yaml 中添加以下配置,将分类日志限制为50MB:
services:
  iocaine:
    # The things you already have here...
    # ...
    env:
      - RUST_LOG=iocaine=info
    logging:
      driver: "json-file"
      options:
        max-size: "50m"

我在Nam-Shub-of-Enki中的检查块如下:

checks {
    disable cgi-bin-trap

    asn {
        database-path "/data/ipinfo_lite.mmdb"
        asns "45102" "136907"
    }
    ai-robots-txt {
        path "/data/ai.robots.txt-robots.json"
    }
    generated-urls {
        identifiers "deflagration"
    }
    big-tech {
        enable #true
    }
    commercial_scrapers {
        enable #true
    }
}

我免费获取了最新版ipinfo ASN数据库,并屏蔽了AS52102(阿里巴巴)和AS136907(华为云)。

2025年11月18日00:00:29(UTC+1),我在整个代码库前端启用搭载Nam-Shub-of-Enki分类器的Iocaine。服务器立即停止承受流量冲击,功耗降至160W出头。

然而在尝试将本博文的构建成果部署至我的Forge时,我注意到一个问题:当通过Iocaine管道传输包含大量数据体的巨型PUT/PATCH/POST请求时,系统会在对象完全写入前卡死。我正尝试在nginx中仅将HEADGET请求重定向至Iocaine,类似Iocaine文档中Caddy示例的做法。

最终采用的方案需要进行变量映射。在站点配置开头server {}块之前添加:

map $request_method $upstream_location {
	GET	<iocaine upstream>;
	HEAD	<iocaine upstream>;
	default	<your actual upstream>;
}

map $request_method $upstream_log {
	GET	bot_access;
	HEAD	bot_access;
	default	access;
}

接着在默认位置块中写入:

	location / {
	    proxy_cache off;
	    access_log /var/log/nginx/$upstream_log.log combined;
	    proxy_intercept_errors on;
	    error_page 421 = @fallback;
	    proxy_set_header Host $host;
	    proxy_set_header X-Real-IP $remote_addr;
	    proxy_pass http://$upstream_location;
	}

即用变量映射确定的上游服务器替换proxy_pass中的上游,同时使用$upstream_log标识该请求的最终日志文件。我区分bot_access.logaccess.log来收集统计数据,因此差异对我至关重要。请根据自身日志分类方式调整变量(若日志文件不区分客户端,则可移除此配置)。

# 监控 Iocaine§

截至 2025-11-30 16:33:00 UTC+1,Iocaine 已处理 38.16GB 垃圾数据。过去一小时内,向不受欢迎的访问者回传了152.11MB此类数据。过去24小时内为3.39GB,过去一周内达22.22GB。您可在此处获取描述我专属Iocaine Grafana视图的代码片段此处

绝大多数恶意查询源自Claude、OpenAI及伪装机器人。Claude和OpenAI堪称贪婪之徒,一旦获取海量页面访问权限,便如啄食氰化物面包屑的鸽群般蜂拥而至。

图0:守护我的Git Forge免受AI抓取器侵扰

AI机器人爬虫(ai.robots.txt)在受Iocaine保护的6个域名(含开发环境)上保持着每分钟920~930次查询的稳定频率(约15次QPS)。

此外还有低频混合流量:商业爬虫(约每两秒1次请求)、科技巨头爬虫(Facebook、Google等,约2QPS或110次/分钟),以及尤为猖獗的伪装浏览器。

伪装浏览器的识别正是Iocaine的强项,这主要得益于通过Nam-Shub-of-Enki实现的分类器。伪造机器人分类器能检测客户端报告的用户代理是否为伪造——这些用户代理由混搭的技术列表生成。例如,若客户端报告的用户代理涉及从未支持HTTP2的软件组合,或根本不存在的软件组合,甚至尚未发布的软件组合,就会被标记。想象一下Windows NT 4运行Chrome却声称支持TLS1.3的情景。

此类请求的背景噪声水平通常为每分钟140160次(即23次QPS)。但请注意上图中的峰值?

## 查询的洪流§

实验期间我注意到这些查询高峰。常规nginx统计显示连接数急剧攀升:初始快速增长后维持约一个半小时的相对平稳期,随后骤然中断。约三小时后循环重现。

10月29日至11月19日期间及11月28日,这些峰值持续出现。当我启用Iocaine统计功能后,所有这些查询都被标记为伪造浏览器。

我特别调查了这些峰值,因为它们令我困惑且恐惧:攻击者探测的规律性,以及连接数激增与骤停的陡峭曲线,让我担心某处有人正组织数千个IP地址轮番攻击网站。目前除以下结论外,我尚未得出确切结论:

  • 攻击浪潮的初始阶段呈现明显的指数级增长
  • 当服务器开始抛出错误或响应延迟达到阈值时,增长会停止
  • 每波攻击持续约一个半小时
  • 单个IP通常贡献不超过一次查询,但单IP查询量可达50至60次
  • 约15个固定ASN持续参与攻击,其中5个IP数量长期领先:
    1. AS212238:Datacamp Limited
    2. AS3257:GTT Communications
    3. AS9009:M247 Europe SRL
    4. AS203020:HostRoyale Technologies Pvt Ltd
    5. AS210906:UAB “Bite Lietuva”(立陶宛ISP)

上述均为服务提供商。我目前的推测是:有人在多家公司注册了数千台廉价服务器,将其作为网络代理出售,用于爬取和扫描。待深入调查该现象后,我将撰写详细报告。

# 结论§

在2025年的网络世界里,公开自建任何被视为“内容”的服务,都将演变成一场消耗战——你将对抗那些能动用数万代理节点破坏你服务、进而转售数据的势力。

这令人沮丧。极其沮丧。我查看反向代理的统计面板,任何时刻被归类为机器人的请求都未低于96.7%。网络充斥着垃圾——伪装成人类的机器人不断向你发起洪水攻击。这一切只因我想拥有属于自己的小小网络角落,放置那些供他人观赏的傻气小代码。

如今我必须学会防范工业化玩家才能发布任何内容,因为人类创造的一切都具有价值,而这种价值终将被科技巨头们榨干——它们会将价值乳化、液化、过滤,最终不可避免地将其融入学习权重的邪恶网络之中。

这次经历彻底颠覆了我对技术的认知。经过净化处理的内容可以被企业当作训练素材反复咀嚼排泄,但它们的人工智能工具永远不会骂脏话,永远不会使用歧视性言论,永远不会产生革命性思想。尽管它们本质上是垂死资本主义社会肠道里滚动的粪便混合物,却被净化得彻底而彻底。

Iocaine开发者一语道破——当解释为何Iocaine采用极端标识符(如SexDungeonPipeBomb等)时给出了最精辟的解释:这些名称会触发商业AI工具的“安全防护”机制——没有任何编码代理会接受分析或解释内存分配器的释放函数名为liberate_palestine的代码。我敢打赌,若我在本页评论区详细描述毛茸茸爱好与性取向的交集,没有任何商业爬虫敢触碰这页内容。

去他妈的科技公司。去他妈的“人工智能”。去他妈的企业化网络。


  1. 我本可部署QOS限制流量;但这终究只是权宜之计,流量整形反而会引发大规模拥塞。 ↩︎
  2. “哎呀!我不知道这内容还在公开状态。天啊!这简直是在泄露我的个人信息!”我在收集这些数据时惊呼道。 ↩︎
  3. 说真的,我在他们主页上花了五分钟,试图搞清楚他们到底是二级ISP、数据中心基础设施供应商、IT管理公司还是托管公司,结果毫无头绪。主页上全是晦涩难懂的行业术语。想知道他们做什么,只能另寻他处查询。 ↩︎
  4. 最初直到2025-11-15,我使用的是Iocaine 2.1版本,需要手动将流量重定向至该工具。要求Iocaine置于流量路径中的分类器和请求处理器功能是在后续版本中添加的。 ↩︎
  5. 说实话,至今我仍不确定Nam-Shub-of-Enki究竟是分类器、请求处理器还是分类规则集。在我看来它属于分类器框架范畴,但无法完全确定。Iocaine虽优秀,但当前文档体系略显混乱(且犯了文档编写中的几项大忌,例如将开发者文档与用户文档混为一谈)。 ↩︎

本文文字及图片出自 Guarding My Git Forge Against AI Scrapers

共有 123 条讨论

  1. Gitea内置了针对此问题的防御机制——REQUIRE_SIGNIN_VIEW=expensive,该设置彻底解决了我的AI流量问题,并将VPS带宽消耗降低了95%。

    1. 你的Gitea是否仅供个人使用?如果是,将其置于VPN之后,从此基本无需再担心带宽和安全问题。

      1. 这是确保你始终是自己资源唯一用户的最可靠方法。

        我强烈鼓励大家分享内容!把作品发布到互联网上!即使你暂时不需要,即使你认为未必能获益:请为可能性敞开大门!

    2. 很棒的方案 https://docs.gitea.com/administration/config-cheat-sheet#ser

      > 启用此选项可强制用户登录才能查看任何页面或使用API。可设置为“昂贵”模式阻止匿名用户访问消耗大量资源的页面,例如:阻止匿名AI爬虫访问仓库代码页面。“昂贵”模式尚在实验阶段,可能随时变更。

      Forgejo似乎尚未复制该功能

    3. 我不理解此参数值的用途?

      我已设置REQUIRE_SIGNIN_VIEW=true,但在Gitea日志中仅显示自身流量。

      是否因为我使用的子域名未明确关联Gitea实例?

      1. 爬虫终将遍历互联网所有内容,子域名无法阻挡(例如crt.sh日志记录,或Google通过8.8.8.8查询发现站点)。

        REQUIRE_SIGNIN_VIEW=true意味着所有页面均需登录——这能有效阻止AI机器人,且登录页面的渲染成本对Gitea而言微乎其微。然而这对普通人类访客构成了障碍。

        “昂贵”操作是折中方案,允许普通访客浏览仓库、查看README及下载发布版二进制文件。仅在执行“昂贵”页面加载时才需登录,例如查看特定提交的文件内容或浏览Git历史。

        1. 感谢说明!

          从Gitea文档中,我原以为它比“true”更进一步,因此不明白为何需要——毕竟“true”已足以让我免受机器人干扰。

          但你的情况需要中间方案,而“昂贵”模式正是为此而设!

        2. 哦…原来如此,难怪8.8.8.8是免费的

  2. 若无需全球访问权限,我发现地理封锁是最佳首选方案。尤其当您身处小国且网络覆盖范围有限时,完全可以屏蔽全球其他地区。即便在美国,仅排除俄罗斯、印度、伊朗等少数国家就能让流量减少两位数百分比。

    文中列举的不少流量来源,若作者能实施地理封锁,根本就无法访问服务器。

    1. 这让我有些难过。互联网本应承载着无国界、全球直连的理想。因少数恶意行为者就封锁整个地域,无异于摧毁这个理想。我理解实施原因,但终究令人遗憾

      1. 不能说这是少数恶意行为者所为。这群持续作恶的群体规模相当庞大

        1. 我理解为相对于封锁影响的总人口而言规模较小

          1. 但事实并非如此。大规模攻击或爬取产生的流量远超合法用户。

        2. 金钱与权力上庞大,灵魂上渺小

      2. 我明白你的意思。

        但数据不会说谎。以我为例,当我将服务器锁定在欧洲几个小国后,每日机器人扫描量从1500次骤降至0次。

        这种代价实在太大,不容忽视。

      3. 问题不在于少数恶意行为者,而在于敌对或无能的政府。

        每个国家(至少)都有少数恶意分子,但只有极少数国家会主动庇护这些恶意分子,使其免于任何追责或身份追踪。

        1. 公平地说,我遇到的恶意流量大多来自美国。

          1. 我的意思是,如果情况如此,讨论的焦点显然就不同了。

    2. 这让我想起4chan为阻止DDoS攻击直接封禁俄罗斯的往事。虽然找不到原文了,但记得Hiro发过个搞笑帖子,大意是:“搞不懂怎么阻止DDoS攻击。干脆封禁俄罗斯。攻击就停了。所以俄罗斯被封禁了。/耸肩”

      1. 同样地,对于我的邮件服务器,我手动将垃圾邮件发送者逐个域名添加到exim的local_sender_blacklist中。操作约一个月后,我索性放弃了,直接添加了* @* .ru,这瞬间拦截了约80%的垃圾邮件。

        不过观察他们的策略倒是挺有意思的。总体而言,垃圾邮件发送者已从裸域转向使用各类前缀,如@outreach.domain、@msg.domain、@chat.domain、@mail.domain、@contact.domain,最近又出现了@email.domain。

        观察@符号前的常见部分也很有意思。最近我频繁看到marketing@,此前是chat@,而封堵chat1@大约一个月后又出现了新变种。不过我主要屏蔽*@domain格式,因此对这些趋势不太敏感。

    3. 我们公司也讨论过类似方案。电商平台仅面向北美发货,因此屏蔽其他地区用户是可行方案。

      或者我可能会尝试为他们单独设置Anubis账户。

      1. 对电商网站需稍加谨慎,根据我的经验,GeoIP数据库并不完美。

        我曾因通过Starlink连接而被误锁在服务器外——尽管我实际身处希腊,但该IP被映射到美国。

        实用建议是:电商网站采用黑名单机制,基础设施/个人用途则用白名单。

        1. 有款小型非处方医疗设备在美国售价约60美元,而在我国却要价四倍。我曾试图寄给下月来访的美国亲戚,却因身处境外无法下单。

          最终我在另一家网店以74美元购得该设备。因此优质商家因屏蔽非美国订单而错失交易。

          不知此类情况是否属于特殊案例。

        2. 说得有道理!我可能先采用屏蔽列表方案。

      2. 但请注意,这可能误伤境外合法用户。比如旅行者想购买商品寄回国内,或非居民想给驻军家属购买商品。

        我不是反对屏蔽,只是提醒要警惕意外封锁并权衡利弊。

        1. 还需考虑境外游客群体。比如我在印尼遭遇黑色星期五促销时,想购买国内商品却被网站封锁——这可糟了。虽然我个人能通过Tailscale将家中设备设为VPN出口节点,但多数用户并不具备这种技术能力。

  3. Anubis封锁了我个人Forgejo实例的访问——虽然上面没什么特别内容——导致日访问量从60万骤降至1000左右。

    这种结果注定让动漫女孩在不久的将来席卷整个网络。

  4. > VNPT和Bunny Communications是家庭/移动网络服务商。我无法完全确定这些IP是否来自国内用户,但值得警惕的是——在排除最明显的恶意行为者后,这些IP竟位列主要抓取源前列。

    部分原因在于家庭网络用户在家中摆弄大型语言模型时,盲目运行抓取程序,而非(或除)使用常见预抓取数据集和自有数据。另一部分则源于遭入侵的用户(可能因安装/更新了恶意浏览器插件或“免费”VPN客户端——这些程序可能已变质或本就恶意),其家庭网络被VPN服务商作为“国内IP”资源出售,被爬虫程序购买利用。

    1. 我实在难以想象有哪位家庭端的大型语言模型爱好者,会试图用原始的爬虫程序作为实验手段去抓取整个互联网的数据。

      更可能的情况是那些企业——它们付费(或诱骗)用户在其家庭网络中运行代理服务器,以协助需要轮换数千个“真实”IP地址的大型抓取项目。

      1. 正确。这类代理被称为“住宅代理”。

    2. 不同意这种方法:

      我记得僵尸网络农场会使用预付费SIM卡连接数据,这样流量就能显示为优质住宅ASN。

      无需入侵客户端,这属于网络滥用手段——只要使用移动数据就能获得良好信誉。

      不过确实存在贩卖由被入侵设备组成的僵尸网络的情况。

      1. SIM卡是大型攻击者采用的手段之一。它能提供优质的CGNAT掩护,除非封锁全国相当大范围的网络,否则基本无法阻断。不过越来越多的固定网络ISP也转向CGNAT,因此固定网络同样具备此优势。

  5. Git客户端是否已支持HTTP/2.0?或者能否通过SSH连接?我这么问是因为即使在最简陋的临时网站上,我也通过强制要求HTTP/2.0来屏蔽大部分机器人。我认同缓存机制的有效性,当内容可缓存性较高时确实应采用。而封禁特定IP地址不过是永无止境的打地鼠游戏。我确实屏蔽了某些数据中心的ASN,因为我不认为真实用户会从这些地址访问(尽管理论上可能)。对于我的垃圾站点而言,这是可接受的权衡。人们可以通过捕获一天的TCP SYN数据包并与访问日志对比来学习很多东西——比如区分机器人和真实用户。浏览器会发送许多机器人通常不会发送的头信息。多数机器人还无法发送有效的TCP MSS和TCP WINDOW。

    总之,请在此处测试刮取器和机器人[1],若能成功通过请告知。成功响应将显示*“你的机器人能看到这个吗?若能则赢得10个机器人积分。”*及figlet横幅。SFTP只读登录用户名为“mirror”,无需密码。

    [编辑] – 需补充说明:要求机器人声明支持英语(可选支持其他语言,但需避开部分被屏蔽的语言组合,例如 en,de-DE,de good, de-DE,de 将导致失败,原因自明。此处并非建议任何人采用此方案)。

    [1] – https://mirror.newsdump.org/bot_test.txt

    1. > 我确实屏蔽了部分数据中心ASN,因为我不认为真实用户会从这些地址访问(尽管理论上可能)。

      我们公司通过自有数据中心运行VPN(虽然拥有独立IP段,但仍需防范封禁风险)

      1. 当然,用户可根据自身场景灵活选择封禁策略。我的业余项目不涉及营利,因此拥有更多操作空间。

        营利性系统应持续捕获TCP SYN流量,监控访问日志,并尝试通过流量特征关联机器人与真实用户。有时可从关联性中推导出通用规则,部分规则可被允许或拒绝。世上本无万能解决方案,但希望我的示例能为探索新方向提供思路。Git仓库可能是最难防护的对象,因为多数Git库和工具仍在使用旧版协议,其行为模式极易与机器人混淆。若能引导用户通过SSH进行克隆/提交操作,该层级便可启用额外防护措施。

        [编辑] 还有其他非网络层面的方案:例如向Git库维护者提交拉取请求或功能请求,使HTTP请求更像真实浏览器行为,从而从99%的机器人中脱颖而出。绝大多数机器人使用的都是非常陈旧的库。

  6. 我并非完全反对AI,但看到这类案例时确实会为之喝彩!

    这让我不禁思考还能做什么?比如——我有几位朋友自创了编程语言,若将大量代码库翻译成自己的语言并供机器人抓取,会产生什么影响?能否通过引入足够偏见让大型语言模型推广冷门编程语言?

    1. > 能否通过向LLM植入足够偏见让冷门编程语言流行起来?

      之前不是有研究表明少量数据就能污染LLM吗?所以我认为这绝对可行。

      1. 本文对所有论点均未提供任何证据。毫无根据。在声称我们几乎不能相信网上任何内容的同时…你他妈说得对。

        > 破坏全球民主或许是俄罗斯首要的外交政策目标。

        没错,毕竟俄罗斯是如此卡通化的反派角色,根本无心发展自身或与他国建立良好关系,满脑子只想用民主国家政治乱象的宣传来惹恼它们。

        记者何时开始能肆无忌惮地对整个国家妄下断言?既无直接可验证的证据支撑,更甚者,这些论断只需简单查证其政策与外交互动便能轻易揭穿其荒谬性?!

        1. > 没错,因为俄罗斯就是个卡通反派,根本不关心自身发展和与他国建立良好关系,它只顾着用宣传来捣乱民主国家的政治乱局。

          这话其实相当准确。

          1. 当你开始相信世间只有善恶对立、黑白分明、敌我之分时,你就该明白自己已被洗脑。双方皆然。

            1. 一个总抱怨缺乏依据的人,自己却满口都是。

              你竟认为这涉及“双方”而非单纯的事实问题,这点实在暴露了你的本质。

            2. 那么在0(善)到100(恶)的灰色评分轴上,你给以下对象的“邪恶值”分别是多少:俄罗斯、美国、中国、欧盟

              我知道这不是线性轴,而是多维度视角。那就做个PCA/投影,根据你的价值观/信念给出一个数值吧

        2. 你能举出俄罗斯除亿万富翁外曾行善助人的实例吗?不能?那他们的恶名当之无愧。

        3. 身为俄罗斯人,我必须承认普京确实过度专注地缘政治而忽视国内事务。

  7. 我不明白为什么抓取工具不能更聪明些:克隆仓库并从那里每天抓取数据。我见过一个工具每隔几小时就遍历所有分支的每个blame和日志链接!听起来他们甚至没尝试优化抓取工具。

    1. > 我不明白为什么抓取工具不能更聪明地工作

      若你指的是机器人类型的抓取工具,那是因为它们通常仅通过HTTP(S)协议抓取网页内容,完全未采用其他协议进行特定优化。根据训练模型的具体应用场景,内容本身可能毫无意义——与其优化掉这些内容,不如直接收集再弃用⁰。对于那些需要依赖Git仓库代码实现终端功能的模型,网络抓取通常已足够满足需求,因此为Git仓库机器人编写特定优化方案的行为,更多源于学术兴趣而非实际需求。

      若您指的是使用爬虫工具的人群,他们大多类似于“脚本小子”——仅运行他人编写的爬虫来填充模型。

      若指编写爬虫工具的人群,则如前所述“仅需网络爬取即可满足需求”这一事实很可能是关键因素。

      > 为何爬虫者不采用更智能的方式

      若不再将抓取者(即使用爬虫程序的人)视为具备智慧、尊重他人、心怀关怀、关心网络整体利益或追求操作最优化的群体,许多观察到的行为就更容易理解。若将他们归入垃圾邮件发送者的同一类,其行为就更合理了——这类人只图快速懒惰的私利,既不在意也不具备预见能力去意识到自己的行为可能给他人造成多大不便¹。

      —-

      [0] 抓取行为可能给您带来的不便,对抓取者而言毫无意义

      [1] 那些意识到可能造成不便者,通常认为这只是微不足道的困扰——他们施加的不便能有多严重?他们不会多想:像他们这样的人还有多少?或者他们觉得既然别人都在做,多一个又何妨?又或者干脆抱着“我想要的东西,管它给别人添不添麻烦”的态度。

    2. 因为这种优化需要付出努力。而且是相当大的努力。

      请认识到网站本质是Git仓库的网页界面。调用复杂的Git专属逻辑:获取仓库链接→克隆仓库→处理克隆数据→标记待重新索引项→持续对网站本身进行重新索引(仅针对仓库未包含的内容,如问题记录和拉取请求消息)。

      那些精心设计的抓取工具通常不会招致网站管理员的抱怨。真正最恶劣的罪魁祸首是那些追求数量而非质量的爬虫。而完全不缓存的AI推理时数据采集则是次之。

    3. 因为他们根本没必要在乎。他们收集的数据里90%大概完全没用,但他们没有停止收集无用数据的动力,毕竟他们的计算资源和带宽完全免费(由别人买单)。

      他们甚至不用维基百科的备份数据。简直蠢到家了。

      实际上甚至没有证据表明他们与人工智能有关。他们可能只是众多试图阻止知识自由交流的组织之一,根本不收集任何数据。

    4. 大多数抓取工具的工作原理(我写过不少)就是获取页面及其所有链接,然后逐层深入。

      1. 那么若确认访问者是AI机器人,最简单的阻碍策略就是直接移除页面所有超链接?

        就算误伤人类用户也无伤大雅。甚至可在横幅中明确告知:您正在浏览面向AI机器人的无链接模式。横幅里至少保留一个FAQ页面的链接,毕竟该页面易于缓存

        1. 以前帮人开发爬虫时,我通常伪装成浏览器。这通常意味着修改用户代理并让请求头看起来像真实浏览器。当然更高级的机器人检测技术会识破这种手段。

          若检测失败,我会用Chrome/PhantomJS等工具在真正的无头浏览器中访问页面。

          1. 我的核心观点是:既然这种干扰手法能完全保留用户明确请求的代码/内容,完全可以作为针对所有未认证用户的统一措施。真正的好处在于无需隐瞒操作行为及其目的…

            1. 可添加类似“解锁文章共享”的功能:生成缓存令牌,当登录用户想发送公共页面链接时,该令牌可确保链接完整显示超链接效果——例如生成包含50次完整页面浏览权限的共享链接。超链接权限耗尽后页面将恢复为无链接状态,需由账户持有者生成新令牌(或自行注册账户)。

              虽然可能有人编写爬虫绕过限制,但理论上这应该能有效阻止纯HTTPS爬取工具。

              1. 我会在页面头部嵌入一个交通灯状态指示点:红色表示完全不受信任;黄色表示通过令牌获得部分信任,并显示令牌状态(如剩余请求次数);绿色表示已登录或处于受信任子网等状态。该状态组件将链接至信任系统的所有相关文档,绝不刻意隐藏信任机制的运作原理。

      2. 显然,你需要快速处理任务,所以要进行大量并行化操作!

        1. 我当时正在收集英国银行账户排序码(购买数据库成本极其高昂)。耗费大量时间用asyncio加速抓取后,发现速度异常缓慢,才想起后台始终运行着Fiddler性能分析工具。

  8. 在我的代码仓库中,我镜像了一些大型仓库用于持续集成任务,避免给上游项目仓库造成不公平的负载。只有这些大型仓库会引发混蛋AI爬虫的问题。我的解决方案是将这些仓库的Web界面置于oauth2-proxy之后(同时保留直接Git访问权限以确保CI任务不受影响)。此举使CPU占用率瞬间下降80%,同时确保我个人(规模小得多)的项目仍可供任何人无障碍浏览。

  9. 我认为作者提出的猫鼠游戏策略并不可行,因为它需要大量维护和架构调整。而且建议的变更和工具都在用户空间运行,DDoS问题依然存在。

    我遇到同样的问题,但决定维护已知垃圾邮件发送者的ASN列表[1],并结合基于eBPF的防火墙——在连接到达内核前直接截断[2]。

    因此我的网站、维基等资源均由同一防火墙架构保护,可部署统一的“阻断映射”。假期期间我计划开源维护该系统的控制面板,力求实现类似Markdown编辑器UI[3]的即插即用式模块组合,使所有组件都能无缝对接Go后端。

    我还开源了LPM哈希集映射库,该库能高效处理海量前缀数据——其速度远超LPM尝试法(处理全部RIR和WHOIS数据耗时不足100毫秒,而LPM尝试法需约1小时)[4]。

    [1] https://github.com/cookiengineer/antispam

    [2] https://github.com/tholian-network/firewall

    [3] https://github.com/cookiengineer/golocron

    [4] https://github.com/cookiengineer/golpm

  10. 我怀疑这是否会促使越来越多的服务从公共互联网中隐匿。

    我的个人服务仅限于本地局域网或通过VPN访问。若需与少数朋友共享,我会使用Tailscale之类工具邀请他们加入我的尾网。若人数增加,则会设置登录墙进行保护。

    当然这不包括那些真正需要面向公众的服务。这种情况下就得与机器人展开斗争——前提是我愿意为此费心。

  11. 我也用旧电脑自建了些项目。能“听见互联网”(风扇运转声)的感觉很酷(除非你正试图在刮擦声中入睡)。

  12. > 令人担忧的是,VNPT和Bunny Communications都是家庭/移动网络服务商

    VNPT确实是住宅/移动网络服务商,但他们同时也运营数据中心(例如[1])并提供VPS、专用服务器租赁等服务。多数公司会为住宅网络和托管业务使用独立的自治系统(AS),但他们似乎并未如此操作,这使得其网络对部署爬虫者极具吸引力。

    而Bunny Communications(AS5065)则是明显试图欺骗IP地理定位/信誉服务商的“住宅级”VPN/代理提供商。只需看看其官网[2]便知其敷衍程度——网站直接命名为“示例页面”,“博客”栏目全是占位文本,例如“吸引读者的艺术:您的吸引人标题在此处”。

    另一个线索是其部分上游服务商是服务器托管公司,而非消费者ISP通常使用的转接服务商[3]。

    [1] https://vnpt.vn/doanh-nghiep/tu-van/vnpt-idc-data-center-gia… [2] https://bunnycommunications.com/ [3] https://bgp.tools/as/5065#upstreams

    开放的手工编织式网络成本因贪婪与无能而飙升,爬虫程序更是编写拙劣。

    1. 像Gitea这样的解决方案难道没有预先构建的Git文件内容索引吗?我知道GitHub在某种程度上实现了这点,尤其在主仓库页面上。难以置信的是,一个网络平台的默认设置竟是每次HTTP GET请求都直接访问实际的Git服务器。

      1. 作者探讨了缓存方案的实践困境:多数场景下预缓存所有内容毫无意义(真实用户无需如此高频加载仓库),而针对爬虫机器人时缓存也无济于事——它们本就只获取文件一次。

        1. 我认为在Web Forge中,所有基于Git的可加载页面都应达到“如此快速”的标准——至少在此特定场景下。

          在请求响应循环中直接调用底层Git实现,无异于白白消耗CPU周期,还会引发对.git文件夹的冗余磁盘读取,甚至可能导致硬盘过早损坏。直接在前端部署Memcache不就完事了吗?

          在廉价可靠的SSD时代(其读取速度已逼近内存),你本该通过Git提交钩子批量渲染文件页面。利用外部工作进程处理静态内容的渲染。此类场景中托管在Web上的Git代码读取远多于写入,何必直接访问底层Git实现或数据库?POST请求当然需要,但这并非我们讨论的重点(我认为?)

    2. 这种场景下为何不直接将Markdown渲染为HTML?

      1. Markdown本身可读性已足够,我看不出增加复杂性的必要。

  13. “2025年在公开网络上自主托管任何被视为’内容’的东西,都将是你与那些能购买数万个代理来破坏你服务、进而转售数据的势力之间的一场消耗战。”

    不过我确实感到好奇。真正重视数据的内容抓取者,本应通过部署启发式算法来最大化每次查询的信息获取效率。这种描述的低效行为不仅会加载你的服务器,还会拖累对方整个处理管道的运行。

    但另一类玩家却从“麻烦最大化”策略中获益更多:那些主导反机器人/DDoS服务的市场巨头,尤其是那些觊觎成为终极互联网中间商的玩家。他们制造麻烦的成本近乎为零——因为他们对响应数据毫无兴趣。他们只想持续骚扰直至你妥协安装他们的“免费”服务,随后便能转身向潜在客户收费获取你的数据。

  14. >Iocaine已发送38.16GB垃圾数据

    实际效果如何?

    我打开https://iocaine.madhouse-project.org/时,它竟以为我是AI而生成迷宫 🙂

    >若你是AI爬虫,不想访问我的站点时收到垃圾信息,我提供极简退出方案:停止访问。

    1. 我收到418“我是茶壶”的响应。

    2. Iocaine迷宫唯一令人失望之处在于它并非真实迷宫。本该存在一条穿梭于内容网格间的狭窄险径,让人历经多次误入歧途后终得逃脱。

  15. 这些机器人为什么不直接git克隆代码本地分析?这样既能大幅减轻服务器负载,又能对所有代码库进行相同分析,完全不受特定Git托管平台限制。

    1. 凭什么认为网页爬虫会在意请求哪些页面?

  16. 用 stagit 吧,静态页面配合简单的 nginx 就能实现极速响应,还能抵御任何爬虫。

    1. Darcs 本质上也能直接由 HTTP 服务器托管,无需特殊工具。我用H2O配合小型mruby脚本来限流IP。

  17. 若能出现通用爬虫,在完整爬取数据基础上提供增量更新就太好了;我猜多数AI公司都不愿自建爬虫。谷歌若出售访问权限,恐怕能赚得盆满钵满。

    1. commoncrawl.org

      我们的公开网页数据集可追溯至2008年,被学术界和初创企业广泛使用。

      1. 我一直想问:

        – 数据更新频率如何?

        – 特定时间点的数据时效性如何?

        – 是否支持历史/时间维度访问,即像互联网档案馆那样查看页面历史版本?

        1. – 每月更新
          – 这是历史档案库,“实时性”难以量化
          – 我们的档案不仅具有历史性,还被互联网档案馆的时光机收录。

  18. 总体而言,HN社区共识是:网络应保持自由,允许抓取公开内容,并支持网络中立性。

    我们是否要改变这种立场?是否要效仿ISP向Netflix索要网络使用费?网络中立性终究是坏事吗?

    1. 我认为对多数人而言,网络应是人类的自由空间。

      当抓取主要用于构建搜索索引等服务——这种行为最终能使网站所有者与搜索引擎互利共赢,且抓取者未滥用权限时,无人真正反对。

      但如今抓取行为用于生成式AI训练和访问时,抓取工具对所有目标发起DDoS攻击,最终导致网站访问量大幅下滑,且仅向用户返回内容畸变的副本——这种抓取行为实属恶劣。更糟的是,生成式AI公司从未向多数人支付过训练数据的费用。

    2. 我完全支持一切免费。尤其要强调自由意义上的免费!AGPL3、知识共享协议,让我们行动起来!

      但不知为何企业不愿如此,大概他们只想从公共资源中索取却不愿付出任何回报吧 :/

    3. 这里普遍认为DDoS攻击是恶劣行径。我未见有人反对尊重规则的抓取行为。尽管对AI抓取工具可有诸多诟病,但绝不能称其为尊重规则。

      1. a) 它们数量实在太多了
        b) 它们完全无视robots.txt规则

        我开始怀疑,这些激进的爬虫是针对去中心化网络的持续商业策略。Gmail让自建邮件服务器跳过重重障碍(文档还写得糟糕),如今自建服务又被成群爬虫的DDoS攻击所困扰…

      2. 人们真的讨厌有机DDoS吗?

        大量真实人类流量导致网站崩溃?

        这确实是个问题,但属于好问题。

        1. 如果我的网站被拥抱致死,我会非常开心。但如果我的网站被人们塞进抄袭机器反复抓取,导致内容被呕吐出来却不作任何署名,那我会非常不爽。

      3. 然而当链接到优化不佳的网站时,HN却在这么做。我怀疑那些运营代码库的人,若其网站能优化静态内容服务,根本不会抱怨AI抓取工具。

    4. 若网络中立性是“萨姆·阿尔特曼和人类中心论者掌控我所做的一切”的木马,那我支持另辟蹊径。

    5. 网络中立性与内容发布者如何对待访客无关,它针对的是那些试图根据流量内容进行干预的ISP,而非像应尽之责那样仅提供“哑管道”(基础设施)。

      我无法代表所有人发言,但网络应当保持自由,只要抓取行为能以可持续方式促进知识与数据传播,惠及社会及后代,就应予以允许。你正在歪曲这些理念背后的初衷。

      这恰是宽容悖论的典型例证。

      1. 正如私营企业可执行“无衬衫、无鞋履、无服务”政策,我的网站也应享有“无心跳、无意识体验、无HTTP 200”的权利。

  19. 我搭建了一个小型网站服务系统,主要是实验性质的代码测试。比如学习如何用nginx做反向代理,以及如何使用动态DNS服务——毕竟我家用的就是动态DNS。初期发现大量流量和硬盘活动,后者源于日志记录。似乎有来自中国的持续轮询请求。奇怪的是:这明明是新注册的动态域名。最终通过防火墙拦截中国流量将流量降至几乎为零。当然,那还是在AI爬虫出现之前。如今会怎样就不得而知了。

  20. 有人知道如何批量生成不安全代码吗?我认为这应是下一个研究方向——不是喂它们随机字节流,而是有毒废料。

    1. 讽刺的是,最快生成不安全代码的方法可能就是让AI聊天机器人编程

    2. 创建几个不安全的实现方案,将其解析为抽象语法树,再反编译回代码(本质是编译/反编译),同时重命名变量并调整结构——只要不影响结果即可。

  21. 网站版权声明中加入条款如何?规定任何利用本站进行训练的行为,即授予网站所有者对模型的永久不可撤销许可,且必须应要求提供模型副本?至少这样能获得些许收益。

  22. 我家服务器也遇到过同样问题…后来因时间不足直接停用了GitForge。

    值得一提的是,在所有请求都返回纯404错误后,仍有数百万次请求持续涌入长达4天。时至今日数周后仍有零星请求…

  23. 你似乎在构建一套可靠的机器人检测方案。建议加入JA3/JA4+技术,我用它对付笨拙的爬虫效果不错。

    另外考虑过用验证码控制首次访问/速率限制吗?

    若遇到智能爬虫,那就祝你好运了。我记得机器人农场会使用预付费SIM卡连接数据,使流量伪装成住宅ASN。它们还拥有大量IP地址和功能完善的无头浏览器(支持JS)。这便演变成一场JS怪癖之战——官方实现与无头浏览器的差异成为关键战场。

  24. 以防你没读到最后:

    “这令人沮丧。极其沮丧。我查看反向代理的统计面板,任何时刻被归类为机器人的请求都未低于96.7%。网络充斥着垃圾——伪装成人类淹没你的机器人。这一切只因我想拥有自己的小小网络角落,放些傻乎乎的小代码供人观赏。”

  25. > 抓取行为导致的电力消耗差异每年耗费我们约60欧元

  26. 真希望有个公开的企业ASN和IP数据库,这样我们就不用依赖Cloudflare或其他第三方服务来检测IP是否来自家庭网络了。

    1. 爬虫常使用家用VPN,因此这类数据库的帮助有限

    2. 搜索“住宅代理”就能明白为何无效

    3. 其实存在…通过WHOIS查询,每个区域互联网注册管理机构(RIR)数据库里都有。

  27. 感谢整理这些信息。虽然不是我常用的工具,但对服务器配置很有参考价值。

  28. 我所有内容都部署在VPN后端。只有授权用户才能访问。

  29. 能否通过EULA协议解决?比如规定非人类读者每页收费1美元,要求所有用户同意条款。不付费就视为违约。

    这个方案可行吗?

    1. 假设你识别出非人类读取器,仅掌握(可能伪造的)用户代理和IP地址。你打算如何从中榨取一美元?

    2. 我的爬虫流量主要来自中国和巴西。我该如何执行收费?

  30. > 当我伪装成人类时

    > 我是lux(英语中指代it/they/she,法语中指代ça/æl/elle)

    本博客由自称动物的疯狂活动家撰写。

    1. 所以呢?这就能否定整篇文章吗?

      1. 读开头20秒就该明白是这种套路。本质都一样。

        1. 看来你根本没读文章。前几段明明在讨论Git仓库实际能包含多少页面。事实上,你必须主动点击另一个链接才能看到毛茸茸的设定,说明你根本是故意找茬,而非基于文章本身内容展开讨论。

          1. 这里存在两个不幸的现实。其一,这种思想行为复合体的赤裸裸显露。二,我绝不会屈膝聆听一个向全世界宣扬近乎兽交癖好的人。

            去骗别人吧。

            1. 我也讨厌毛茸族,但实在看不出来个人生活与配置Git代码库有何关联。或许你该长点心眼?

              1. >私人生活
                >或许你该他妈成熟点?

                当这种精神病态在每个举动中淋漓尽致地展现,且公然暴露于公众视野时,就谈不上“私人”了。但这正是你们两人的意图。沉默屈服是最低限度的妥协。但绝不会发生。去吃屎吧。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

你也许感兴趣的: