0%

记一次绕过币安API地区限制的折腾经历

请在符合国家法律法规的前提下食用本文!

币安被美国罚款 43 亿美元!CEO 辞职!
虽然币安很早以前就禁止美国用户注册,但是现在币安的 API 也开始限制美国 IP 了,导致我的机器人从宣布罚款第二天开始就无法正常使用。直到今天,我终于忍无可忍,决定想办法绕过这个限制。

环境介绍

简单描述一下我的机器人:

1
用户 -> Discord -> 托管在Cloudflare Worker上的Discord Bot -> 币安API

换句话说,无论用户来自哪里,币安收到的 API 请求都是通过 Cloudflare Worker 发出的。而由于 Discord 服务器主要位于美国,因此到达 Cloudflare Edge 的地域也几乎都是美国,所以币安理所应当认为这些请求都是来自美国的。

所以很简单,我需要找到一个办法,可以让 Cloudflare Worker 发出的请求看起来像是来自其他国家的。

解决方案 1

经过一通搜索,成功找到了这篇文章和作者的演示视频

虽然其原理我依然有点一知半解,但经过一整天的测试,终于成功复现了作者说明的方法。以下是步骤:

假如我们有一个 Cloudflare Worker,承担核心的 API 功能,名字是demoworker,代码如下:

1
2
3
4
5
export default {
async fetch(request, env, ctx) {
return new Response("Hello World!");
},
};

同时,我们有一个域名,假如是logiconsole.com

创建一个代理 Worker

首先,我们需要创建一个代理 Worker,就叫demoworkerproxy好了。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
async function proxy(request) {
var headers = request.headers;
var { pathname } = new URL(request.url);
return fetch(`https://demoworker.logiconsole.com${pathname}`, {
body: request.body,
headers: headers,
method: request.method,
redirect: "manual",
cf: {
resolveOverride: "demoworker.logiconsole.com",
},
});
}

async function forceRegion(request) {
return fetch(request.url, {
headers: request.headers,
body: request.body,
method: request.method,
redirect: "manual",
cf: {
resolveOverride: "twdemoworkerproxy.logiconsole.com",
},
});
}

addEventListener("fetch", (event) => {
return event.respondWith(
["US", "CN"].includes(String(event.request.cf.country))
? forceRegion(event.request)
: proxy(event.request)
);
});

先不用管上面代码的含义,后面会解释。但记住logiconsole.com是我自己的域名,到时候要改成你的域名。

创建 Worker Routes

然后,我们需要创建两个 Worker Routes,分别指向上面的两个 Worker,如下图所示:

注意把域名改成自己的域名。

创建 DNS A 记录

接下来,我们需要创建两个 DNS A 记录,分别指向两个 Worker Routes。这里要注意,通常我们会直接在 Worker 的 Triggers 中添加 Custom Domain,让 Cloudflare 自动帮我们创建类型是 Worker 的 DNS 记录,但是这里我们需要手动创建 A 记录,并且将 IP 地址设置为任意一个 Cloudflare Warp 的 IP 地址,如下图所示:

图中的188.114.96.3就是一个 Cloudflare Warp 的 IP 地址,你也可以自己去找其他能用的 IP。可以看到,我还添加了一个twdemoworkerproxy的记录,对应的 IP 地址8.39.126.5同样是一个 Cloudflare Warp 的 IP 地址,但是位于台湾。

解释

当有一个请求访问demoworkerproxy.logiconsole.com时,由于该域名被指向了 Cloudflare 的网络,且设置了 Worker Routes,所以它被指向了demoworkerproxy这个 Worker。通过这段代码:

1
2
3
4
5
6
7
addEventListener("fetch", (event) => {
return event.respondWith(
["US", "CN"].includes(String(event.request.cf.country))
? forceRegion(event.request)
: proxy(event.request)
);
});

Worker 会先判断请求的来源地区,如果是美国或者中国,就会走forceRegion方法。(把中国也加进来是方便本地测试)

1
2
3
4
5
6
7
8
9
10
11
async function forceRegion(request) {
return fetch(request.url, {
headers: request.headers,
body: request.body,
method: request.method,
redirect: "manual",
cf: {
resolveOverride: "twdemoworkerproxy.logiconsole.com",
},
});
}

forceRegion的方法简单来说,就是在请求中添加cf:{resolveOverride: 'twdemoworkerproxy.logiconsole.com'},再原封不动向自己发送一遍请求。由于resolveOverride的存在,Cloudflare 会去解析twdemoworkerproxy.logiconsole.com这个域名,而这个域名指向的是 Cloudflare 在台湾的机房 IP,且同样通过*demoworkerproxy.logiconsole.com/*这个 Worker Route 指向了demoworkerproxy。所以 Cloudflare 会通过台湾的机房再请求一次demoworkerproxy。又因为twdemoworkerproxy.logiconsole.comdemoworkerproxy.logiconsole.com处于同一个域名下,所以请求中的所有信息都会被透明地传递下来。

接下来,我们打开 Worker 的日志,并且访问demoworkerproxy.logiconsole.com,可以看到如下日志:

其中较早的信息如下:

很明显是我本地的 IP 地址,而较晚的信息如下:

注意 headers 中的访问来源信息已经不是中国了(但居然是英国,在我之前的测试中,应该统一都是台湾的信息。可能是 IP 信息乱了),而’colo’这个值变成了TPE,即台北机场的代码。

既然访问来源已经不是 US 或者 CN 了,那么就不会再走forceRegion方法,而是走proxy方法,也就是直接向demoworker发送请求,即正常访问原本的 API 了。

查找不同地区 Cloudflare 的 IP 段

首先,可以通过这个地址下载最新的 geolite 数据库,其中的GeoLite2-ASN可以查找 IP 段对应的 ASN,GeoLite2-Country可以查找 IP 段对应的国家。只要找到 ASN 为 13335、组织是 CLOUDFLARENET 的 IP 段,就是 Cloudflare 的 IP 段了。接下来和国家的 IP 段互相对应,就能找到不同地区的 Cloudflare IP 段了。
另外,Linux 下可以通过nmap -n -sP {IP段}这个命令扫描该 IP 段下所有可用的 IP 地址。

万万没想到

然而用了这个方法之后,我发现我的机器人依然无法正常工作。经过反复测试验证后,我才不得不承认,币安貌似是把 Cloudflare 所有的 IP 段都给封了……

解决方案 2

既然方案 1 行不通,那就只能来简单粗暴的了:找个机房,写一个简单的代理脚本,把所有的请求都转发到该机房,再由该机房转发到币安。这样,币安就会认为所有的请求都是来自该机房了。
没什么好说的,直接上仓库:
https://github.com/dale0525/binance-server.git

经过反复衡量采用了 Docker 方案,方便在不同机房迁移。在 Docker 前面加一个反向代理即可,如果实在偷懒,直接访问 IP:端口也是可以的。

另外,推荐一个开源的运维管理面板:1Panel
比宝塔透明,并且至少 SSL 证书续签从来没遇到问题。

总结

本文其实主要是记录一下 Cloudflare Worker 强制指定机房的方法,毕竟方案 2 没什么好说的。