如标题,我确信已经发现了一个简单的绝妙的免梯反代 “任意接口” 的方法,隐藏 ip 调用接口不在话下,这里空白的地方刚刚好,水一贴。
背景
有时候需要在服务器上跑些接口,但是又不想暴露源站服务器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 的目的。
缺陷
- 之所以是 “任意” ,因为做了防护的接口反代会失败
- workers 仍然存在不可删除头暴露反代的域名信息,使用的时候需要知道你的域名会暴露出去,具体自行查看
- 当前代码 UA 和 Refer 是硬编码,如果有强烈需求,可以带在 url 参数里面,改代码实现自定义头,不过建议加个标志,防止真正的参数被误处理
例如,当参数以{self_prefix}
开头的认为自定义头,其它的则是原有参数
测试
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
}'
其它
写着好麻烦,后面的说明有点水了,将就看吧。
参考
以及发现曾经看到的代码的帖子,解决部署在vercel上ChatGPTNextWeb(NextChat)无法正常调用proxy.cocopilot.org上chat API问题! - 常规话题 / 人工智能 - LINUX DO