# Cloudflare Workersをpass-through proxiesとして悪用する (IP rotation, FireProx-style)

{{#include ../../banners/hacktricks-training.md}}

Cloudflare Workersは、上流のターゲットURLがクライアントによって指定される透明なHTTP pass-through proxiesとしてデプロイできます。リクエストはCloudflareのネットワークから送出されるため、ターゲット側にはクライアントではなくCloudflareのIPsが見えます。これはAWS API Gateway上のよく知られたFireProx手法を踏襲しますが、Cloudflare Workersを使用します。

### 主な機能
- すべてのHTTPメソッド（GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD）をサポート
- ターゲットはクエリパラメータ（?url=...）、ヘッダ（X-Target-URL）、あるいはパス内にエンコード（例：/https://target）して渡せる
- 必要に応じてhop-by-hop/ヘッダフィルタリングを行いながらヘッダとボディをプロキシ
- ステータスコードと大半のヘッダを保持してレスポンスを返送
- （Workerがユーザー制御ヘッダから設定する場合など）X-Forwarded-Forの偽装が可能
- 複数のWorkerエンドポイントをデプロイしてリクエストを扇形に広げることで、非常に高速かつ容易にローテーション可能

### 動作の仕組み（フロー）
1) クライアントがWorkerのURL（`<name>.<account>.workers.dev` またはカスタムドメインルート）にHTTPリクエストを送信する。  
2) Workerはターゲットをクエリパラメータ（?url=...）、X-Target-URLヘッダ、あるいは実装されていればパスセグメントから抽出する。  
3) Workerは受信したメソッド、ヘッダ、ボディを指定された上流URLへ転送する（問題のあるヘッダはフィルタリング）。  
4) 上流のレスポンスはCloudflare経由でクライアントにストリーミングされる。オリジン側にはCloudflareのIPsが見える。

### Worker 実装例
- クエリパラメータ、ヘッダ、またはパスからターゲットURLを読み取る
- 安全なヘッダのサブセットをコピーし、元のメソッド/ボディを転送
- 任意でユーザー制御ヘッダ（X-My-X-Forwarded-For）やランダムIPを使用してX-Forwarded-Forを設定
- 寛容なCORSを追加し、preflightを処理

<details>
<summary>pass-through proxying用のサンプル Worker (JavaScript)</summary>
```javascript
/**
* Minimal Worker pass-through proxy
* - Target URL from ?url=, X-Target-URL, or /https://...
* - Proxies method/headers/body to upstream; relays response
*/
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
try {
const url = new URL(request.url)
const targetUrl = getTargetUrl(url, request.headers)

if (!targetUrl) {
return errorJSON('No target URL specified', 400, {
usage: {
query_param: '?url=https://example.com',
header: 'X-Target-URL: https://example.com',
path: '/https://example.com'
}
})
}

let target
try { target = new URL(targetUrl) } catch (e) {
return errorJSON('Invalid target URL', 400, { provided: targetUrl })
}

// Forward original query params except control ones
const passthru = new URLSearchParams()
for (const [k, v] of url.searchParams) {
if (!['url', '_cb', '_t'].includes(k)) passthru.append(k, v)
}
if (passthru.toString()) target.search = passthru.toString()

// Build proxied request
const proxyReq = buildProxyRequest(request, target)
const upstream = await fetch(proxyReq)

return buildProxyResponse(upstream, request.method)
} catch (error) {
return errorJSON('Proxy request failed', 500, {
message: error.message,
timestamp: new Date().toISOString()
})
}
}

function getTargetUrl(url, headers) {
let t = url.searchParams.get('url') || headers.get('X-Target-URL')
if (!t && url.pathname !== '/') {
const p = url.pathname.slice(1)
if (p.startsWith('http')) t = p
}
return t
}

function buildProxyRequest(request, target) {
const h = new Headers()
const allow = [
'accept','accept-language','accept-encoding','authorization',
'cache-control','content-type','origin','referer','user-agent'
]
for (const [k, v] of request.headers) {
if (allow.includes(k.toLowerCase())) h.set(k, v)
}
h.set('Host', target.hostname)

// Optional: spoof X-Forwarded-For if provided
const spoof = request.headers.get('X-My-X-Forwarded-For')
h.set('X-Forwarded-For', spoof || randomIP())

return new Request(target.toString(), {
method: request.method,
headers: h,
body: ['GET','HEAD'].includes(request.method) ? null : request.body
})
}

function buildProxyResponse(resp, method) {
const h = new Headers()
for (const [k, v] of resp.headers) {
if (!['content-encoding','content-length','transfer-encoding'].includes(k.toLowerCase())) {
h.set(k, v)
}
}
// Permissive CORS for tooling convenience
h.set('Access-Control-Allow-Origin', '*')
h.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD')
h.set('Access-Control-Allow-Headers', '*')

if (method === 'OPTIONS') return new Response(null, { status: 204, headers: h })
return new Response(resp.body, { status: resp.status, statusText: resp.statusText, headers: h })
}

function errorJSON(msg, status=400, extra={}) {
return new Response(JSON.stringify({ error: msg, ...extra }), {
status, headers: { 'Content-Type': 'application/json' }
})
}

function randomIP() { return [1,2,3,4].map(() => Math.floor(Math.random()*255)+1).join('.') }
```
</details>

### FlareProx を使ったデプロイとローテーションの自動化

FlareProx は Cloudflare API を使用して多数の Worker エンドポイントをデプロイし、それらを順にローテートする Python ツールです。これにより Cloudflare’s network からの FireProx のような IP ローテーションが可能になります。

セットアップ
1) “Edit Cloudflare Workers” テンプレートを使って Cloudflare API Token を作成し、ダッシュボードから Account ID を取得します。
2) FlareProx を設定する:
```bash
git clone https://github.com/MrTurvey/flareprox
cd flareprox
pip install -r requirements.txt
```
**flareprox.json の config file を作成する:**
```json
{
"cloudflare": {
"api_token": "your_cloudflare_api_token",
"account_id": "your_cloudflare_account_id"
}
}
```
**CLI の使用方法**

- N 個の Worker proxies を作成:
```bash
python3 flareprox.py create --count 2
```
- endpoints を一覧表示:
```bash
python3 flareprox.py list
```
- ヘルスチェックエンドポイント:
```bash
python3 flareprox.py test
```
- すべての endpoints を削除する:
```bash
python3 flareprox.py cleanup
```
**Routing traffic through a Worker**
- クエリパラメータ形式:
```bash
curl "https://your-worker.account.workers.dev?url=https://httpbin.org/ip"
```
ヘッダー形式:
```bash
curl -H "X-Target-URL: https://httpbin.org/ip" https://your-worker.account.workers.dev
```
- パス形式（実装されている場合）:
```bash
curl https://your-worker.account.workers.dev/https://httpbin.org/ip
```
- 手法の例:
```bash
# GET
curl "https://your-worker.account.workers.dev?url=https://httpbin.org/get"

# POST (form)
curl -X POST -d "username=admin" \
"https://your-worker.account.workers.dev?url=https://httpbin.org/post"

# PUT (JSON)
curl -X PUT -d '{"username":"admin"}' -H "Content-Type: application/json" \
"https://your-worker.account.workers.dev?url=https://httpbin.org/put"

# DELETE
curl -X DELETE \
"https://your-worker.account.workers.dev?url=https://httpbin.org/delete"
```
**`X-Forwarded-For` 制御**

Worker が `X-My-X-Forwarded-For` を尊重する場合、上流の `X-Forwarded-For` 値に影響を与えられます:
```bash
curl -H "X-My-X-Forwarded-For: 203.0.113.10" \
"https://your-worker.account.workers.dev?url=https://httpbin.org/headers"
```
**プログラムでの使用方法**

FlareProxライブラリを使用して、エンドポイントの作成、一覧表示、テストを行い、Pythonからリクエストをルーティングします。

<details>
<summary>Pythonの例: ランダムな Worker エンドポイント経由で POST を送信</summary>
```python
#!/usr/bin/env python3
from flareprox import FlareProx, FlareProxError
import json

# Initialize
flareprox = FlareProx(config_file="flareprox.json")
if not flareprox.is_configured:
print("FlareProx not configured. Run: python3 flareprox.py config")
exit(1)

# Ensure endpoints exist
endpoints = flareprox.sync_endpoints()
if not endpoints:
print("Creating proxy endpoints...")
flareprox.create_proxies(count=2)

# Make a POST request through a random endpoint
try:
post_data = json.dumps({
"username": "testuser",
"message": "Hello from FlareProx!",
"timestamp": "2025-01-01T12:00:00Z"
})

headers = {
"Content-Type": "application/json",
"User-Agent": "FlareProx-Client/1.0"
}

response = flareprox.redirect_request(
target_url="https://httpbin.org/post",
method="POST",
headers=headers,
data=post_data
)

if response.status_code == 200:
result = response.json()
print("✓ POST successful via FlareProx")
print(f"Origin IP: {result.get('origin', 'unknown')}")
print(f"Posted data: {result.get('json', {})}")
else:
print(f"Request failed with status: {response.status_code}")

except FlareProxError as e:
print(f"FlareProx error: {e}")
except Exception as e:
print(f"Request error: {e}")
```
</details>

**Burp/Scanner 統合**
- ツール（例: Burp Suite）を Worker URL に向ける。
- ?url= または X-Target-URL を使って実際の upstream を指定する。
- HTTP のセマンティクス（methods/headers/body）は保持され、送信元 IP は Cloudflare の背後に隠される。

**運用上の注意と制限**
- Cloudflare Workers Free プランではアカウントあたり概ね 100,000 リクエスト/日が許容される。必要なら複数のエンドポイントでトラフィックを分散すること。
- Workers は Cloudflare のネットワーク上で実行されるため、多くのターゲットは Cloudflare の IP/ASN のみを認識する。これにより単純な IP の許可/拒否リストやジオヒューリスティックを回避できる可能性がある。
- 責任を持って、かつ必ず許可を得た上で使用すること。ToS と robots.txt を順守すること。

## References
- [FlareProx (Cloudflare Workers pass-through/rotation)](https://github.com/MrTurvey/flareprox)
- [Cloudflare Workers fetch() API](https://developers.cloudflare.com/workers/runtime-apis/fetch/)
- [Cloudflare Workers pricing and free tier](https://developers.cloudflare.com/workers/platform/pricing/)
- [FireProx (AWS API Gateway)](https://github.com/ustayready/fireprox)

{{#include ../../banners/hacktricks-training.md}}
