Menutup origin — WAF yang bisa dilewati bukan WAF
Ini kesalahan konfigurasi paling umum pada arsitektur Cloudflare di depan AWS, dan yang paling jarang diperiksa — karena situsnya bekerja sempurna meski salah.
Intisari
- IP origin yang bisa dihubungi langsung = seluruh lapisan Cloudflare terlewati.
- IP origin bocor lewat riwayat DNS, sertifikat, header email, dan halaman error — bukan rahasia.
- Dua perbaikan: kunci security group ke rentang IP Cloudflare, atau Cloudflare Tunnel tanpa ALB publik.
- Tunnel lebih rapat: tidak ada IP publik sama sekali, tidak ada inbound port yang terbuka.
- SSL mode wajib Full (strict). Flexible mengirim plaintext ke origin dan bisa membuat loop redirect.
Serangannya sesederhana ini
# Cari IP origin — biasanya tidak sulit
dig +short portal-alb-123456.ap-southeast-3.elb.amazonaws.com
# Lalu lewati Cloudflare sepenuhnya
curl -H 'Host: portal.contoh.id' https://<ip-alb>/akun
| Yang terlewati | Akibatnya |
|---|---|
| WAF | Payload SQLi/XSS langsung ke aplikasi |
| Rate limiting | Credential stuffing tanpa batas ke halaman login |
| Bot protection | Scraping penuh isi berbayar |
| Cache | Setiap permintaan memukul origin |
| DDoS protection | Origin-mu terekspos langsung |
cf-connecting-ip | Bisa dipalsukan — rate limit aplikasimu ikut jebol |
Baris terakhir itu menghubungkan kembali ke Fase 1. Di sana kita memakai
cf-connecting-ip untuk rate limiting karena "tidak bisa ditimpa klien". Itu benar
hanya kalau satu-satunya jalan masuk adalah lewat Cloudflare. Kalau origin bisa dihubungi
langsung, penyerang tinggal mengirim header itu sendiri dengan nilai apa pun — dan seluruh pembatas
yang berbasis IP jadi tidak berarti.
IP origin bukan rahasia
| Sumber kebocoran | Catatan |
|---|---|
| Riwayat DNS | Arsip publik menyimpan record dari sebelum Cloudflare dipasang |
| Certificate Transparency | Setiap sertifikat yang pernah diterbitkan tercatat publik |
| Header email | Email dari servermu membawa IP-nya |
| Subdomain yang tidak di-proxy | staging., mail., ftp. — abu-abu, bukan oranye |
Halaman error & phpinfo | Sisa dari CI3 |
| Pemindai internet | Mencocokkan sertifikat di seluruh ruang IPv4 secara berkala |
Kesimpulannya: jangan bergantung pada kerahasiaan IP. Asumsikan sudah diketahui, lalu pastikan mengetahuinya tidak berguna.
Perbaikan 1: kunci security group
# Ambil rentang IP Cloudflare
curl -s https://www.cloudflare.com/ips-v4 -o /tmp/cf4.txt
curl -s https://www.cloudflare.com/ips-v6 -o /tmp/cf6.txt
# Terapkan ke security group ALB
SG=sg-0123456789abcdef0
while read -r cidr; do
aws ec2 authorize-security-group-ingress \
--group-id "$SG" --protocol tcp --port 443 --cidr "$cidr" \
--description "Cloudflare" 2>/dev/null
done < /tmp/cf4.txt
| Kelebihan | Kekurangan |
|---|---|
| Perubahan kecil, mudah dipahami | Rentang IP Cloudflare berubah sesekali |
| Tidak menambah komponen | Butuh otomatisasi pembaruan, atau situsmu mati suatu hari |
| ALB tetap seperti biasa | Batas jumlah aturan per security group bisa tercapai |
| — | Pelanggan Cloudflare lain juga berasal dari IP itu |
Baris terakhir sering terlewat. Membatasi ke IP Cloudflare berarti "hanya lalu lintas yang melewati Cloudflare" — bukan "hanya lalu lintas yang melewati zona Cloudflare-ku". Siapa pun yang punya akun Cloudflare bisa mengarahkan zona miliknya ke IP origin-mu dan lolos filter itu. Tutupnya: verifikasi sertifikat klien (Authenticated Origin Pulls) atau header rahasia yang ditambahkan Cloudflare dan diperiksa origin-mu.
Cloudflare → Transform Rules → Modify Request Header:
Set static: X-Origin-Token = <nilai acak panjang dari Secrets Manager>
// src/middleware/asal.ts
export const hanyaLewatCloudflare = defineMiddleware(async (ctx, next) => {
const token = ctx.request.headers.get("x-origin-token");
if (token !== env.ORIGIN_TOKEN) {
return new Response("Forbidden", { status: 403 });
}
return next();
});
Perbaikan 2: Cloudflare Tunnel (lebih rapat)
Dengan ALB publik:
Internet → ALB (IP publik) → ECS
↑ bisa dihubungi siapa saja
Dengan Tunnel:
Internet → Cloudflare → terowongan keluar ← cloudflared (sidecar di ECS)
tidak ada IP publik, tidak ada port masuk yang terbuka
cloudflared berjalan sebagai kontainer sidecar di task ECS yang sama dan membuka koneksi
keluar ke Cloudflare. Tidak ada satu pun port masuk yang terbuka — bahkan tidak ada
alamat untuk dituju.
{
"family": "portal",
"networkMode": "awsvpc",
"containerDefinitions": [
{
"name": "web",
"image": "…/portal:abc123",
"portMappings": [{ "containerPort": 4321 }],
"essential": true
},
{
"name": "cloudflared",
"image": "cloudflare/cloudflared:2026.8.0",
"command": ["tunnel", "--no-autoupdate", "run"],
"secrets": [
{ "name": "TUNNEL_TOKEN", "valueFrom": "arn:aws:secretsmanager:…:portal/tunnel:token::" }
],
"essential": true,
"dependsOn": [{ "containerName": "web", "condition": "START" }]
}
]
}
| Kelebihan | Kekurangan |
|---|---|
| Tidak ada IP publik sama sekali | Satu kontainer lagi per task |
| Tidak ada biaya ALB | Health check & deployment butuh penyesuaian |
| Tidak ada rentang IP yang harus dipelihara | Ketergantungan tambahan pada Cloudflare |
| Tidak perlu sertifikat di origin | Menelusuri masalah jaringan jadi kurang langsung |
Yang mana untukmu? Kalau kamu sedang membangun dari awal, Tunnel lebih sederhana dan lebih aman — dan menghapus biaya ALB. Kalau kamu memigrasikan dari CI3 yang sudah di belakang ALB, kunci security group plus header rahasia lebih sedikit perubahan dan bisa dipasang minggu ini. Keduanya menutup lubangnya; yang penting adalah salah satunya benar-benar dipasang.
SSL mode: Full (strict), bukan yang lain
| Mode | Cloudflare → origin | Verdict |
|---|---|---|
| Off | HTTP | Tidak pernah |
| Flexible | HTTP polos | Tidak pernah — dan sumber loop redirect |
| Full | HTTPS, sertifikat tidak diverifikasi | Rentan MITM di jalur Cloudflare→origin |
| Full (strict) | HTTPS, sertifikat diverifikasi | Yang benar |
Mode Flexible adalah penyebab klasik loop redirect tak berujung. Cloudflare menghubungi origin lewat HTTP; origin melihat HTTP dan mengalihkan ke HTTPS; Cloudflare menerima redirect itu dan meminta ulang lewat HTTP; dan seterusnya. Gejalanya "ERR_TOO_MANY_REDIRECTS" yang muncul untuk sebagian pembaca dan tidak untuk yang lain, tergantung cache.
Untuk ALB, pakai sertifikat ACM. Untuk origin lain, Cloudflare Origin CA gratis dan berlaku 15 tahun. Dengan Tunnel, ini tidak berlaku sama sekali — terowongannya sudah terenkripsi.
Verifikasi — lakukan ini, jangan diasumsikan
IP=<ip-origin-mu>
# 1. Harus TIMEOUT atau ditolak, bukan menjawab
curl -m 5 -H 'Host: portal.contoh.id' "https://$IP/" -k -sS -o /dev/null -w '%{http_code}\n'
# 2. Tanpa header rahasia, harus 403
curl -m 5 -H 'Host: portal.contoh.id' "https://$IP/berita/uji" -k -si | head -1
# 3. cf-connecting-ip palsu tidak boleh dipercaya
curl -sS https://portal.contoh.id/api/uji-ip -H 'CF-Connecting-IP: 1.2.3.4'
# 4. SSL mode
curl -sI http://portal.contoh.id/ | head -3 # harus 301 ke https, tanpa loop
Latihan: temukan IP origin-mu sendiri seperti penyerang akan melakukannya — periksa riwayat DNS domainmu dan log Certificate Transparency untuk domainmu. Lalu jalankan uji nomor 1: kalau origin-mu menjawab, kamu baru saja menemukan bahwa seluruh lapisan keamanan Cloudflare-mu opsional. Tutup dengan salah satu dari dua perbaikan, lalu jalankan ulang seluruh empat uji.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.