一个简单绝妙的免梯反代 “任意接口” 的方法

如标题,我确信已经发现了一个简单的绝妙的免梯反代 “任意接口” 的方法,隐藏 ip 调用接口不在话下,这里空白的地方刚刚好,水一贴。

一个简单绝妙的免梯反代 openai 的方法

背景

有时候需要在服务器上跑些接口,但是又不想暴露源站服务器ip,免费代理又不靠谱,因此需要一个简单的隐藏自己 ip 的方法请求接口。

举个例子:
论坛里发了不少第三方 api 中转,如果我是想钓鱼的,我就把 UA 为 Go-http-client/2.0 的请求 ip 记录下来,大概率是用 oneapi 中转的服务器源站的 ip ,如果还被从 Refer 头中拿到了源站域名,意味着在这个域名上关于 cloud flare 的防护都失效了。

其它方案

基于上面提到的需求,隐藏服务器源站 ip 请求接口,想到了用 cloud flare 的 workers 做反代,例如对 GitHub 的反代,论坛里应该有类似的贴子,不过多概述,这样的方案就是每一个反代的源站都需要创建 workers ,过于麻烦。

因此在此基础上,可以增加一个 host_map 的映射,即你的一个 host 对应一个反代的源站,这样的好处是一个 workers ,只需要改动 host_map 和触发器即可。

示例代码:

该代码简单的由 AI 生成,未做验证,使用自行测试

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

const host_map = {
  'www.yourdomain1.com': 'https://origin1.com',
  'www.yourdomain2.com': 'https://origin2.com',
  // 添加更多的映射...
}

async function handleRequest(request) {
  let url = new URL(request.url)
  let host = url.host

  if (host in host_map) {
    url.hostname = new URL(host_map[host]).hostname
    let newRequest = new Request(url, request)
    newRequest.headers.set('Host', new URL(host_map[host]).hostname)
    return await fetch(newRequest)
  } else {
    return await fetch(request)
  }
}

当前方案

于是需要一个可以反代 “任意接口” 的方案,该方案不需要很好的健壮性,因为仅仅是针对接口上的请求,下面是该方案的实现。

workers 代码:

const IPHeaders = [
  'x-real-ip',
  'x-forwarded-for',
  'x-client-ip',
  'cf-connecting-ip',
  'true-client-ip',
  'x-cluster-client-ip',
  'x-forwarded',
  'forwarded-for',
  'x-proxyuser-ip',
]

const userAgents = [
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537',
  'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134',
  'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0',
  // Add more user agents if you want
]

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  try {
    const workersURL = new URL(request.url)
    let targetURL = workersURL.pathname.slice(1) // Remove the leading '/'

    if (!targetURL) {
      return fetch(request)
    }

    let target = new URL(targetURL)

    let newRequest = new Request(target, {
      method: request.method,
      headers: request.headers,
      body: request.body
    })

    newRequest.headers.set('Host', target.host)
    newRequest.headers.set('Referer', target.origin)
    newRequest.headers.set('User-Agent', userAgents[Math.floor(Math.random() * userAgents.length)])

    IPHeaders.forEach(header => {
      newRequest.headers.delete(header)
    })

    let response = await fetch(newRequest)

    // Add CORS headers
    let corsHeaders = {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': '*',
      'Access-Control-Max-Age': '86400',
    }

    // Create a new response with CORS headers
    let corsResponse = new Response(response.body, {
      ...response,
      headers: corsHeaders
    })

    return corsResponse
  } catch (error) {
    // handle error
    return new Response(error.toString(), {status: 500})
  }
}

触发器配置一个 Custom Domains 即可。

简单的说,就是将需要反代的请求 URL 拼接在反代域名上,处理后由 workers 向反代 URL 发请求,并且删除相关的包含源服务器的头,达到隐藏源站 ip 的目的。

缺陷

  1. 之所以是 “任意” ,因为做了防护的接口反代会失败
  2. workers 仍然存在不可删除头暴露反代的域名信息,使用的时候需要知道你的域名会暴露出去,具体自行查看
  3. 当前代码 UA 和 Refer 是硬编码,如果有强烈需求,可以带在 url 参数里面,改代码实现自定义头,不过建议加个标志,防止真正的参数被误处理
    例如,当参数以 {self_prefix} 开头的认为自定义头,其它的则是原有参数

测试

测试使用的三方 API 帖子

curl --request POST \
  --url https://proxy.3211000.xyz/https://furryapi.vscode.top/v1/chat/completions \
  --header 'Authorization: Bearer sk-4KcRLHPrqgu5voGjC2DcB4501b23470980C93dEe8c53E4F2' \
  --header 'content-type: application/json' \
  --data '{
    "messages": [
        {
            "role": "system",
            "content": "You are an AI programming assistant."
        },
        {
            "role": "user",
            "content": "hello"
        }
    ],
    "model": "gpt-3.5-turbo",
    "temperature": 0.1,
    "top_p": 1,
    "n": 1,
    "stream": false
}'

其它

写着好麻烦,后面的说明有点水了,将就看吧。 :joy:

参考

找到曾经看到的代码了, gaboolic/cloudflare-reverse-proxy: cloudflare反向代理|OpenAI/ChatGPT 免翻墙代理|github免翻墙代理|github下载加速|google代理|cloudflare万能代理

以及发现曾经看到的代码的帖子,解决部署在vercel上ChatGPTNextWeb(NextChat)无法正常调用proxy.cocopilot.org上chat API问题! - 常规话题 / 人工智能 - LINUX DO

21 个赞

url的参数好歹encode一下啊。其实说worker,ip到目标服务器基本都是一个::103 结尾的地址。

1 个赞

不想增加使用者的负担,简单的能用就行 :joy:

ip不是自己ip就行了,防护者20%的力拦80%的攻击,这个反代方案也是20%的出力,能反代80%网站就可以了 :crazy_face:

那么不带ua,可以避免这个问题吗?

45 个赞

你是说硬编码这个Ua吗,如果workers反代不带ua,就是用你请求提供的ua

oneapi提供的ua是go-client,我没看oneapi怎么改,就在workers里面写死了

好的,我似懂非懂

1 个赞

‘Access-Control-Allow-Origin’ 这个header一般要不要加呢

响应头?貌似可以加

没考虑健壮性,几乎什么都没考虑 :joy: 给chatgpt写了能用,然后服务器看了请求过来的请求头确认没啥服务器信息后,就没考虑其它的了

还可以用国内云厂商的云函数

这是为什么?

45 个赞

不知道群佬怎么做的防护,反正反代群佬的 cocopilot.org 不行,假设要自己做防护,可以对 cloudflare ip 做拦截,也可以对我说的那个不可删除的 worker 头中做判断拦截

1 个赞

群佬是始皇吗?

看网站,不太了解这一方面,刚刚测下来
可行:
https://proxy.3211000.xyz/https://www.baidu.com
https://proxy.3211000.xyz/https://youtube.com
不可行:
https://proxy.3211000.xyz/https://google.com

1 个赞

嗯。

1 个赞

还可以这么玩 :100:,但是看了YouTube也不行

48 个赞

因为是相对链接,直接拼在 proxy.3211000.xyz 上了,之前想了可以用 refer 提取目标 url 后拼接成新的链接, 302 跳转过去保持下一次的 refer 可用,但是太复杂了,并且兼容性不好,还有改 html meta 的 base_url (貌似是,不确定),这些方案感觉都不太正规…就没考虑了

我记得很早之前 GitHub 看到过类似可以反代所有网站的 worker ,不过搜了很久没找到。

2 个赞

是不是指第一次请求到网页之后然后需要再从相对链接请求其他内容然后请求失败

对,所以适合反代接口,因为不需要考虑各种跳转,并且 post 接口还一点都不好做防护 :joy:,比如我自己的大部分接口理论上也可以被这个方案反代

1 个赞

现在看不太懂,不过感觉是大佬,先放书签吃灰,过一段时间再看