Lewati ke konten utama

Same-Origin Policy dan Web Proxy: Analisis Keamanan Teknis

Ditulis oleh
Smith
Smith
Waktu baca
14 menit baca
Dipublikasikan pada
2 Mar 2026
Same-Origin Policy dan Web Proxy: Analisis Keamanan Teknis

Waktu kami membangun ProxyOrb, ada satu paradoks fundamental yang selalu muncul di setiap keputusan desain: web proxy bekerja dengan cara membuat browser berpikir bahwa konten pihak ketiga adalah konten same-origin. Itu artinya, secara definisi, kita sedang "menipu" model keamanan inti browser. Padahal browser modern sudah menghabiskan lima belas tahun menambahkan lapisan pertahanan yang semakin canggih โ€” justru untuk melawan kebingungan asal (origin confusion) seperti ini.

Artikel ini membahas ketegangan tersebut dari prinsip pertama. Kalau kamu adalah security researcher, penetration tester, atau browser security engineer yang ingin memahami cara web proxy berinteraksi dengan kebijakan same-origin โ€” bukan di level konseptual, tapi di level HTTP header, source code Chromium, dan trade-off engineering produksi โ€” artikel ini untuk kamu.

Kita akan membahas fondasi SOP, URL rewriting, CORS, CORB/CORP, COEP/COOP, Service Worker, iframe, dan implikasi keamanan bagi operator proxy maupun penggunanya.


1. Fondasi Same-Origin Policy

Kebijakan same-origin (SOP) didefinisikan oleh tiga komponen: scheme + host + port. Dua URL dianggap same-origin hanya jika ketiga komponen tersebut cocok persis. https://example.com:443 dan http://example.com:80 adalah cross-origin meskipun menunjuk ke server yang sama.

Yang sering disalahpahami adalah apa yang sebenarnya dicegah oleh SOP versus apa yang diizinkannya. SOP tidak memblokir:

  • Memuat gambar (<img src>) lintas asal
  • Memuat script (<script src>) lintas asal
  • Memuat stylesheet (<link rel="stylesheet">) lintas asal
  • Menanamkan iframe lintas asal (meskipun isi dokumen yang disematkan diisolasi)
  • Mengirim form submission (<form action>) lintas asal

Yang SOP benar-benar cegah adalah membaca respons dari permintaan lintas asal yang dibuat via fetch() atau XMLHttpRequest. Permintaannya tetap keluar โ€” network round-trip tetap terjadi โ€” tapi body dan header responsnya disembunyikan dari JavaScript yang berjalan di origin yang berbeda.

Perbedaan ini sangat penting untuk web proxy. Seluruh tugas proxy adalah menggabungkan dua origin (server proxy dan server target) menjadi satu, menghilangkan batas lintas asal. Begitu semua resource tampak berasal dari https://proxyorb.com, pembatasan SOP soal membaca respons tidak berlaku lagi.

"Celah sah" yang dimanfaatkan web proxy adalah URL rewriting: alih-alih https://example.com/api/data, setiap permintaan jadi https://proxyorb.com/api/data?__pot=aHR0cHM6Ly9leGFtcGxlLmNvbQ==. Dari sudut pandang browser, ini adalah permintaan same-origin. SOP bukan di-bypass โ€” SOP dibuat tidak relevan dengan mengubah origin yang terlihat dari semua konten.


2. Arsitektur URL Rewriting ProxyOrb

Untuk memahami implikasi keamanannya, kamu perlu memahami mekanisme encoding-nya. ProxyOrb menggunakan parameter URL bernama __pot (proxy origin token) yang berisi target origin yang di-encode dalam Base64.

Parameter __pot

Parameter __pot selalu meng-encode origin (scheme + host, tanpa path) dari target, bukan URL lengkap. Artinya https://example.com/some/deep/path?foo=bar dan https://example.com/other/page keduanya menghasilkan nilai __pot yang sama: aHR0cHM6Ly9leGFtcGxlLmNvbQ== (encoding Base64 dari https://example.com). Path dan query string aslinya dipertahankan apa adanya di path dan query string URL proxy.

Ketika pengguna mengakses https://proxyorb.com/?__pot=aHR0cHM6Ly9leGFtcGxlLmNvbQ==, gateway men-decode-nya dan merekonstruksi URL asli:

-- Gateway pseudocode: decoding the proxy request

function resolve_original_url(proxy_url):
    pot_value = parse_query_param(proxy_url, "__pot")
    if not pot_value:
        return error("Missing origin token")

    original_origin = base64_decode(pot_value)
    -- e.g. "https://example.com"

    validate_not_private_ip(original_origin)  -- SSRF protection

    -- Replace the proxy host with the target host, keep path/query intact
    original_url = replace_origin(proxy_url, original_origin)
    return original_url

Gateway kemudian meneruskan permintaan ke server target sesungguhnya, menulis ulang header Origin agar server upstream melihat domain-nya sendiri, bukan domain proxy:

-- Set outbound headers toward the target server

request.headers["Host"]   = target_host
request.headers["Origin"] = target_origin   -- e.g. "https://example.com"
-- Remove all internal proxy headers before forwarding

URL Rewriting Sisi Client via Service Worker

Gateway menangani sisi server. Sisi client โ€” menulis ulang URL di respons HTML, JavaScript, dan CSS agar semua sub-permintaan terus melewati proxy โ€” ditangani oleh Service Worker.

Transformasi intinya mengubah URL apapun yang ditemukan di konten halaman ke format proxy:

-- Service Worker pseudocode: toProxyURL()

function toProxyURL(originalUrl, currentPageUrl):
    if isSameOrigin(originalUrl, currentPageUrl):
        return originalUrl   -- already proxy-origin, no rewrite needed

    -- Extract path/query/hash from the original URL
    -- Build a new URL rooted at the proxy origin
    proxyPath   = extractPathAndQuery(originalUrl)
    potValue    = base64encode(extractOrigin(originalUrl))
    proxyUrl    = proxy_origin + proxyPath + "?__pot=" + potValue

    return proxyUrl

Misalnya, https://cdn.example.com/bundle.js yang direferensikan di dalam halaman yang sedang diproxy menjadi https://proxyorb.com/bundle.js?__pot=aHR0cHM6Ly9jZG4uZXhhbXBsZS5jb20=.

URL rewriting ini berlaku menyeluruh: mencakup fetch(), XMLHttpRequest, <script src>, <img src>, koneksi WebSocket, dan tag <link>. Ketika setiap URL di halaman mengarah ke origin proxy, browser tidak pernah membuat permintaan cross-origin โ€” setiap permintaan adalah same-origin by construction.

Memulihkan __pot Tanpa Full Navigation

Ada edge case yang cukup halus: permintaan yang berasal dari dalam halaman yang diproxy tapi tidak memiliki parameter __pot โ€” misalnya, fetch('/api/data') relatif yang ditembak sebelum Service Worker sempat menulis ulang URL, atau permintaan dari script yang diinjeksikan secara dinamis dan melewati URL rewriter.

Service Worker menyelesaikan token yang hilang via pencarian bertingkat:

-- Service Worker pseudocode: recovering the origin token

function resolveMissingPot(fetchEvent):
    candidates = [
        getUrlOfControlledTab(fetchEvent.clientId),   -- most reliable
        inferUrlFromFetchEvent(fetchEvent),             -- from clientId / resultingClientId
        fetchEvent.request.referrer,                    -- referrer header
    ]

    for url in candidates:
        pot = extractQueryParam(url, "__pot")
        if pot: return pot

    return null   -- cannot recover; let the gateway handle or reject

Gateway memiliki jalur pemulihan paralel: jika permintaan tiba tanpa __pot tapi membawa header Referer yang menunjuk ke URL same-origin yang menyertakan __pot, gateway mengekstrak token dari referer dan melampirkannya ke permintaan saat ini. Ini menangani skenario navigasi di mana token sudah dihapus oleh JavaScript halaman sebelum gateway menerima permintaan.


3. CORS: Sistem Izin Cross-Origin Eksplisit

CORS (Cross-Origin Resource Sharing) dirancang agar server bisa opt in ke akses lintas asal dengan mengirimkan header respons tertentu. Dari perspektif proxy, CORS menciptakan dua masalah berbeda.

Masalah 1: Intersepsi CORS Preflight

Ketika JavaScript di sebuah halaman membuat permintaan fetch() dengan header non-sederhana (misalnya Authorization, Content-Type: application/json), browser mengirimkan permintaan preflight OPTIONS terlebih dahulu. Jika respons preflight server target tidak menyertakan header CORS yang permisif, permintaan aslinya akan diblokir.

Di arsitektur ProxyOrb, Service Worker mencegat semua permintaan OPTIONS dan menjawabnya secara sintetis โ€” bahkan sebelum mencapai gateway โ€” mengembalikan respons yang membuka blokir permintaan sebenarnya:

-- Service Worker pseudocode: synthetic CORS preflight

function handlePreflight(request):
    origin = request.headers["Origin"] or "*"

    return Response(status=204, headers={
        "Access-Control-Allow-Origin":      origin,
        "Access-Control-Allow-Methods":     "GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD",
        "Access-Control-Allow-Headers":     "*",
        "Access-Control-Allow-Credentials": "true",
        "Access-Control-Max-Age":           "86400",
        "Vary":                             "Origin",
    })

Di level gateway, setiap respons yang diproxy menerima header CORS setara:

-- Gateway pseudocode: set CORS on outbound response

response.headers["Access-Control-Allow-Origin"]      = original_origin
response.headers["Access-Control-Allow-Headers"]     = "*"
response.headers["Access-Control-Allow-Credentials"] = "true"

Masalah 2: Permintaan Dengan Kredensial

Kombinasi Access-Control-Allow-Credentials: true dengan Access-Control-Allow-Origin yang bukan wildcard itu signifikan. CORS mengharuskan nilai origin yang eksplisit (bukan *) kapanpun kredensial disertakan. Service Worker mengeluarkan semua permintaan keluar dengan credentials: 'include', jadi gateway harus mengembalikan origin peminta yang persis โ€” bukan wildcard.

Artinya semua cookie yang tersimpan di bawah proxyorb.com โ€” terkumpul dari setiap situs target yang dikunjungi pengguna lewat proxy โ€” dikirim di setiap permintaan yang diproxy. Ini disengaja (untuk mempertahankan status sesi untuk situs yang sudah login), tapi ini juga merupakan pertimbangan keamanan penting yang kita bahas di Bagian 8.

Pola Strip-and-Replace Header CORS

Respons yang diproxy mungkin membawa header CORS dari server target yang salah dari perspektif browser (mereka mereferensikan origin target, bukan origin proxy). Service Worker melakukan strip dan replace:

-- Service Worker pseudocode: sanitize response headers

function sanitizeResponseHeaders(response):
    headers = copy(response.headers)

    -- Remove target-site directives that would confuse the browser
    headers.delete("Content-Security-Policy")
    headers.delete("Content-Security-Policy-Report-Only")
    headers.delete("X-Frame-Options")
    headers.delete("X-Content-Type-Options")

    -- Replace with proxy-origin-correct CORS headers
    headers.set("Access-Control-Allow-Origin",      proxy_origin)
    headers.set("Access-Control-Allow-Credentials", "true")
    headers.set("Access-Control-Allow-Headers",     "*")
    headers.set("Vary", "Origin")

    return headers

4. CORB dan CORP: Pertahanan Lebih Ketat dari Chromium

CORS beroperasi berdasarkan opt-in eksplisit dari server. Chromium menambahkan dua mekanisme yang aktif secara default, terlepas dari konfigurasi CORS.

Cross-Origin Read Blocking (CORB)

CORB diperkenalkan di Chrome 67 (2018) sebagai bagian dari mitigasi Spectre. Inti pemahamannya: bahkan jika body respons cross-origin tidak pernah dibaca oleh JavaScript, fakta bahwa ia sudah di-fetch dan di-decode oleh renderer process berarti ia ada di address space proses itu. Serangan kelas Spectre lalu bisa mengekstraknya via side channel.

CORB mencegah respons cross-origin tertentu masuk ke renderer process sama sekali. Lebih spesifiknya, ketika tag <script> atau <img> men-fetch respons cross-origin dan respons itu memiliki Content-Type berupa text/html, text/xml, atau application/json, Chromium memeriksa body (menggunakan MIME-type sniffer yang didefinisikan dalam spesifikasi CORB) dan, jika tipenya cocok, mengganti respons dengan respons kosong sebelum renderer melihatnya.

Untuk web proxy, CORB akan berdampak buruk jika permintaan benar-benar cross-origin. API endpoint yang mengembalikan application/json yang di-fetch dari tag <script> akan diam-diam mengembalikan kosong. Namun, karena ProxyOrb menulis ulang semua URL menjadi same-origin, kondisi cross-origin CORB tidak pernah terpicu โ€” browser tidak pernah melihat respons JSON cross-origin, karena dari perspektifnya, semua respons berasal dari proxyorb.com.

Satu kasus di mana CORB penting adalah selama periode transisi sebelum Service Worker sepenuhnya terdaftar dan mencegat permintaan. Jika ada permintaan yang lolos dari URL rewriting selama jendela itu, CORB mungkin memblokirnya. Race condition inilah mengapa ProxyOrb juga mempertahankan lapisan interceptor main-thread yang mem-patch XMLHttpRequest, fetch, dan DOM attribute setter secara sinkron sebelum JavaScript halaman manapun berjalan โ€” memberikan fallback selama startup Service Worker.

Perlu dicatat bahwa CORB sebagian sudah digantikan oleh Opaque Response Blocking (ORB), yang sedang dalam proses diadopsi oleh Chromium. ORB menyempurnakan aturan CORB untuk mengurangi false positive sambil mempertahankan perlindungan Spectre. Implikasi kompatibilitas proxy-nya serupa.

Cross-Origin Resource Policy (CORP)

CORP, yang didefinisikan dalam spesifikasi Fetch, memungkinkan server menyatakan bahwa resource mereka hanya boleh dimuat oleh konteks same-origin atau same-site:

Cross-Origin-Resource-Policy: same-origin

Ketika Chromium menemukan header ini pada permintaan sub-resource cross-origin, ia memblokir respons sepenuhnya. Ini lebih agresif dari CORB โ€” berlaku terlepas dari jenis konten dan tidak bisa di-bypass dengan MIME sniffing.

Sekali lagi, karena URL rewriting ProxyOrb memastikan semua permintaan adalah same-origin dari perspektif browser, header CORP dari server target tidak memicu pemblokiran. Gateway juga mem-strip header ini dari respons secara defensif, menangani edge case di mana permintaan lolos tanpa URL rewriting.

Isu lebih dalam dengan CORP sebenarnya adalah kasus di mana arsitektur proxy membantu kompatibilitas: jika https://api.example.com dan https://www.example.com keduanya sedang diproxy, keduanya dipetakan ke origin proxy yang sama, sehingga fetch dari satu ke yang lain kini genuinely same-origin โ€” pembatasan CORP tidak lagi berlaku di antara keduanya.


5. COEP dan COOP: Isolasi Lintas Asal

Mulai Chrome 92 (2021), akses ke SharedArrayBuffer โ€” dan secara tidak langsung, timer beresolusi tinggi yang digunakan untuk API performa tertentu โ€” dibatasi untuk halaman yang telah opt in ke isolasi lintas asal. Opt-in ini membutuhkan dua header respons yang bekerja bersama-sama.

Cross-Origin-Embedder-Policy (COEP)

Cross-Origin-Embedder-Policy: require-corp

Ketika sebuah halaman mengirimkan header ini, browser memastikan bahwa setiap sub-resource yang dimuat halaman tersebut:

  1. Merupakan same-origin, ATAU
  2. Mengirimkan Cross-Origin-Resource-Policy: cross-origin secara eksplisit, ATAU
  3. Memiliki respons CORS yang permisif untuk credentialed fetch

Masalah untuk web proxy: jika situs target mengirimkan COEP: require-corp pada dokumen utamanya, dan dokumen itu dilayani melalui proxy dengan header yang dipertahankan, browser kini menuntut agar setiap sub-resource yang dimuat halaman tersebut juga opt in. Resource apapun yang tidak melakukannya โ€” dan kebanyakan tidak akan โ€” menyebabkan network error.

Cross-Origin-Opener-Policy (COOP)

Cross-Origin-Opener-Policy: same-origin

COOP mengontrol apakah sebuah halaman bisa berbagi browsing context group dengan halaman cross-origin. Ketika diatur ke same-origin, navigasi cross-origin membuka browsing context group baru, memutus referensi window.opener dan channel postMessage antara halaman dan opener cross-origin manapun.

Untuk proxy, COOP tidak langsung merusak seperti COEP, tapi tetap merusak situs yang mengandalkan alur postMessage lintas asal (alur OAuth popup adalah contoh yang paling umum).

Dilema Operator Proxy

Ini adalah trade-off paling sulit yang kita hadapi di ProxyOrb:

Opsi A: Strip COEP dan COOP dari respons.

  • Pro: Pemuatan sub-resource berjalan normal; halaman yang diproxy tidak menerapkan pembatasan ini.
  • Kontra: Kita menghapus header keamanan yang sengaja dipasang situs target. Jika situs menggunakan isolasi lintas asal untuk melindungi data sensitif dari serangan kelas Spectre, menghapus header ini mengekspos kembali risiko itu.

Opsi B: Pertahankan COEP dan COOP.

  • Pro: Maksud keamanan situs target dihormati.
  • Kontra: Sub-resource apapun yang tidak secara eksplisit menetapkan CORP: cross-origin akan gagal dimuat, merusak sebagian besar aplikasi web kompleks.

Strategi ProxyOrb saat ini adalah Opsi A: gateway mem-strip Cross-Origin-Embedder-Policy dan Cross-Origin-Opener-Policy dari respons. Ini memaksimalkan kompatibilitas situs. Trade-off keamanannya dibuat secara sadar: pengguna web proxy menerima bahwa mereka menjalankan konten di lingkungan yang berbeda dari konteks deployment yang dimaksudkan.

Setiap mekanisme keamanan browser baru mengikuti pola: diperkenalkan sebagai opt-in (situs bisa mengirim header jika mereka ingin perlindungan), kemudian secara bertahap dijadikan default untuk API baru, dan akhirnya dipertimbangkan untuk penegakan wajib. COEP mengikuti jalur ini: opsional di Chrome 83, diperlukan untuk SharedArrayBuffer di Chrome 91. Situs yang menyematkan konten pihak ketiga tanpa koordinasi mendapati kontennya rusak. Web proxy memperparah masalah ini karena mereka memediasi konten pihak ketiga secara definisi.

Komunitas keamanan browser menyadari masalah ini. Proposal Document-Isolation-Policy yang sedang berkembang bertujuan memisahkan isolasi proses dari persyaratan isolasi lintas asal, yang berpotensi memungkinkan mendapatkan mitigasi Spectre tanpa mengharuskan semua sub-resource opt in. Ketika itu sudah rilis, kompatibilitas proxy dengan header isolasi mungkin akan membaik.


6. Service Worker sebagai Lapisan Kepercayaan Sisi Browser

Service Worker bukan sekadar optimisasi โ€” ia secara arsitektural esensial untuk model keamanan ProxyOrb. Ini alasannya.

Scope Registrasi Terikat ke Origin

Service Worker didaftarkan dengan scope yang selalu berada dalam origin halaman yang mendaftarkan. Ketika ProxyOrb mendaftarkan Service Worker-nya, scope-nya adalah https://proxyorb.com/, artinya ia mencegat setiap fetch dari halaman manapun di bawah origin tersebut.

Inilah alasan fundamental mengapa URL rewriting ke same-origin berhasil: begitu SW mengontrol client, setiap permintaan jaringan dari client itu โ€” terlepas dari URL apa yang coba di-fetch oleh JavaScript di halaman โ€” melewati Service Worker terlebih dahulu.

// Service Worker entry point
self.addEventListener('fetch', (event) => {
  event.respondWith(handleProxyRequest(event))
})

Pipeline Intersepsi

Ketika Service Worker mencegat permintaan, ia berjalan melalui beberapa tahap keputusan:

-- Service Worker pseudocode: request interception pipeline

function handleProxyRequest(fetchEvent):
    request = fetchEvent.request

    -- Stage 1: Synthetic CORS preflight (never hits the network)
    if request.method == "OPTIONS":
        return syntheticCORSResponse(request)

    -- Stage 2: Pass through requests that shouldn't be proxied
    if shouldBypass(request.url):
        return originalFetch(request)

    -- Stage 3: Ensure __pot is present; recover from context if missing
    enrichedRequest = attachOriginToken(request, fetchEvent)

    -- Stage 4: Forward to gateway
    response = originalFetch(enrichedRequest)

    -- Stage 5: Strip and replace security headers in the response
    return sanitizeAndReturn(response)

Forwarding Header Transparan

Satu tantangan halus: browser membatasi JavaScript untuk mengatur header permintaan "forbidden" tertentu (Host, Origin, Referer, dll.) via Fetch API. Service Worker menyiasatinya dengan meng-encode header yang dibatasi ke dalam satu custom passthrough header; gateway kemudian men-decode dan menerapkannya sebelum meneruskan ke server target:

-- Pseudocode: encode browser-restricted headers for the gateway

function addPassthroughHeaders(request, outboundHeaders):
    restricted = {}
    for name, value in request.headers:
        if name not in COMMON_ALLOWED_HEADERS:
            restricted[name] = value

    if restricted is not empty:
        outboundHeaders["X-Proxy-Passthrough"] = json_encode(restricted)

-- Gateway side: decode and apply before forwarding upstream
function applyPassthroughHeaders(incomingHeaders):
    encoded = incomingHeaders["X-Proxy-Passthrough"]
    if encoded:
        for name, value in json_decode(encoded):
            request.headers[name] = value
        request.headers.delete("X-Proxy-Passthrough")

Implikasi Keamanan SW sebagai Perantara Tepercaya

Dari perspektif keamanan, Service Worker menempati posisi istimewa: ia bisa memeriksa, memodifikasi, dan memalsukan permintaan apapun yang dibuat dari halaman manapun dalam scope-nya. Untuk penggunaan proxy yang sah, memang itulah tujuannya. Untuk proxy jahat, ini akan menjadi attack surface yang sangat kuat.

Inilah mengapa kepercayaan pada script Service Worker itu sendiri sangat penting. ProxyOrb melayani script interceptor dari origin-nya sendiri melalui HTTPS dengan cache control yang ketat. Jika penyerang berhasil menginjeksikan Service Worker yang dimodifikasi, mereka bisa mencegat semua traffic dari pengguna yang terdampak โ€” bukan hanya traffic proxy, tapi permintaan apapun dari halaman di bawah origin itu.


7. iframe: Masalah Frame-Ancestors

iframe menghadirkan tantangan tersendiri dibandingkan sub-resource biasa karena melibatkan browsing context bersarang dengan navigasinya sendiri, batas SOP-nya sendiri, dan serangkaian pembatasan embedding-nya sendiri.

X-Frame-Options dan frame-ancestors

Dua mekanisme mencegah halaman disematkan dalam iframe:

Legacy: X-Frame-Options: DENY atau X-Frame-Options: SAMEORIGIN

Modern: Content-Security-Policy: frame-ancestors 'none' atau frame-ancestors 'self'

Ketika gateway mem-proxy halaman target yang mengirimkan salah satunya, halaman tidak bisa disematkan dalam iframe di bawah origin proxy. Karena X-Frame-Options: SAMEORIGIN mereferensikan origin target (example.com), dan proxy melayani halaman dari proxyorb.com, pemeriksaan same-origin browser gagal.

Proxy harus mem-strip header ini dari respons yang diproxy dan mengganti CSP dengan versi yang permisif:

-- Gateway pseudocode: override embedding-restrictive headers

response.headers.delete("X-Frame-Options")
response.headers.delete("Content-Security-Policy")
response.headers.delete("Content-Security-Policy-Report-Only")

-- Set a permissive replacement that allows the proxy to embed content
response.headers["Content-Security-Policy"] =
    "upgrade-insecure-requests; frame-ancestors 'self'; " +
    "default-src * data: blob: about: ws: wss: 'unsafe-inline' 'unsafe-eval'"

Intersepsi iframe dan Injeksi Script

iframe yang disematkan menghadirkan masalah kedua: kontennya dimuat dari proxy, tapi browsing context iframe tidak secara otomatis memiliki Service Worker atau main-thread interceptor yang aktif. Jika halaman yang diproxy membuat <iframe src="https://widget.example.com/...">, URL iframe itu juga harus ditulis ulang ke format proxy, dan script interceptor proxy harus diinjeksikan ke dokumen iframe.

Interceptor iframe beroperasi di dua level:

Level 1 โ€” Prototype patching (menangkap pembuatan iframe secara programatik):

-- Pseudocode: intercept iframe src assignment

override HTMLIFrameElement.prototype.src setter:
    if value is not already a proxy URL:
        value = toProxyURL(value)   -- rewrite to proxy format
    call original setter(value)
    scheduleProxyInjection(this)    -- inject interceptor into iframe document

Level 2 โ€” MutationObserver fallback (menangkap iframe yang dimasukkan lewat DOM):

-- Pseudocode: observe DOM for dynamically added iframes

observer = new MutationObserver(mutations):
    for mutation in mutations:
        for node in mutation.addedNodes:
            if node is an <iframe>:
                rewriteSrcIfNeeded(node)
                injectProxyScript(node)

observer.observe(document, { childList: true, subtree: true })

Masalah Atribut sandbox

Atribut HTML sandbox membatasi apa yang bisa dilakukan iframe: sandbox="allow-scripts allow-same-origin" mengontrol eksekusi script, form submission, akses lintas asal, dll. Agar injeksi proxy berfungsi, iframe perlu menjalankan script dan memiliki akses ke konteks proxy induk.

Token allow-same-origin ini sangat bernuansa: ketika hadir bersama allow-scripts, ia mengalahkan isolasi origin sandbox โ€” iframe berjalan dengan origin halaman embedding. Ketika tidak ada, iframe mendapatkan opaque origin unik, yang akan merusak injeksi script proxy sepenuhnya.

Pendekatan ProxyOrb saat ini untuk atribut sandbox adalah menghapus atribut sandbox sepenuhnya sebelum menginjeksikan script proxy:

-- Pseudocode: handle sandbox attribute before proxy injection

function handleSandboxedIframe(iframe):
    if iframe.hasAttribute("sandbox"):
        -- Remove so the proxy can inject scripts and access contentWindow
        iframe.removeAttribute("sandbox")
    injectProxyScript(iframe)

Ini adalah trade-off keamanan yang signifikan: sandboxing sengaja dipasang oleh situs asli untuk membatasi kemampuan konten yang disematkan. Menghapusnya memperluas apa yang bisa dilakukan konten tersebut. Ini adalah jenis keputusan yang tidak terlihat oleh pengguna akhir tapi secara material memengaruhi postur keamanan sesi proxy.


8. Implikasi Keamanan bagi Operator Proxy

Lanskap Attack Surface

Ketika pengguna menjelajah melalui ProxyOrb, beberapa kategori data sensitif mengalir melalui origin proxy:

Cookie Sesi: Karena semua situs target diproxy melalui proxyorb.com, cookie disimpan di bawah origin itu. Sesi autentikasi pengguna dengan bank, email, dan media sosial mereka semuanya adalah cookie di bawah satu domain. credentials: 'include' dari Service Worker berarti cookie ini menyertai setiap permintaan yang diproxy.

Header Referer: Header Referer yang dikirim ke server upstream mengungkapkan halaman apa yang dilihat pengguna. Proxy dengan hati-hati mem-strip domain-nya sendiri dari nilai referer sebelum meneruskan ke server target. Jika permintaan berasal dari https://proxyorb.com/some/path?__pot=..., header Referer keluar direkonstruksi sebagai URL target asli (https://example.com/some/path) โ€” domain proxy tidak pernah bocor ke server upstream.

-- Pseudocode: normalize referer before forwarding upstream

function sanitizeReferer(referer):
    if referer is a proxy URL:
        return reconstruct_original_url(referer)   -- e.g. "https://example.com/path"
    if referer's origin equals proxy_origin:
        return ""   -- suppress: don't leak proxy domain to upstream
    return referer

Konteks Eksekusi JavaScript: Setiap file JavaScript yang dilayani melalui proxy dimodifikasi (URL ditulis ulang) dan dieksekusi di origin proxy. Script jahat dari evil.example.com yang diproxy melalui ProxyOrb berjalan di origin proxyorb.com dan memiliki akses penuh ke local storage, cookie, dan IndexedDB origin itu โ€” yang mencakup data dari setiap situs target lain yang diakses pengguna melalui proxy.

Model Ancaman Proxy Jahat

Untuk tujuan edukasi, ada baiknya kita eksplisit tentang apa yang bisa dilakukan proxy jahat yang sengaja tidak dilakukan ProxyOrb:

  1. Credential Harvesting: Proxy jahat bisa mencatat setiap request body (berisi password dan data form) saat melewati gateway.

  2. Session Hijacking: Karena semua cookie situs target disimpan di bawah domain proxy, operator proxy jahat bisa mengakses cookie tersebut di sisi server via gateway.

  3. Content Injection: Proxy secara niscaya memodifikasi konten halaman (untuk menginjeksikan Service Worker dan menulis ulang URL). Proxy jahat bisa menginjeksikan JavaScript sembarang โ€” keylogger, crypto miner, script ad fraud โ€” yang tidak terlihat oleh pengguna.

  4. SSL Stripping: Jika proxy menurunkan koneksi HTTPS ke HTTP untuk bagian gateway-ke-pengguna, semua traffic jadi plaintext.

ProxyOrb beroperasi melalui HTTPS end-to-end dan tidak mencatat request body. Operator web proxy manapun memiliki kemampuan ini, itulah mengapa memilih operator proxy yang terpercaya sama pentingnya dengan memilih penyedia VPN yang terpercaya.

Konten Campuran (Mixed Content)

Browser modern memberlakukan pemblokiran mixed content: halaman HTTPS tidak bisa memuat sub-resource HTTP. ProxyOrb menangani ini dengan memberlakukan HTTPS pada semua koneksi keluar dari gateway, bahkan ketika URL target menggunakan HTTP. Override CSP menyertakan upgrade-insecure-requests untuk menginstruksikan browser meng-upgrade URL sub-resource HTTP apapun ke HTTPS sebelum memuatnya.

Ini umumnya diinginkan, tapi bisa merusak situs yang sengaja melayani resource melalui HTTP (CDN legacy, resource localhost, dll.).


9. Perlombaan Senjata yang Terus Berlanjut: Kesimpulan

Ketika kita mulai membangun ProxyOrb, tantangan kompatibilitas utama adalah CORS dan X-Frame-Options. Sejak saat itu, Chromium sudah mengirimkan CORB, CORP, COEP, COOP, dan sedang mengembangkan Document-Isolation-Policy. Arahnya sudah jelas: browser semakin agresif dalam menegakkan batas lintas asal, dan setiap mekanisme baru mengharuskan infrastruktur proxy untuk beradaptasi.

Tantangan paling signifikan ke depan kemungkinan adalah deployment penuh COEP di aplikasi web besar. Situs yang menggunakan SharedArrayBuffer untuk performa (editor video, IDE, alat kolaborasi) semakin banyak yang mengatur COEP: require-corp. Karena ProxyOrb mem-strip header ini untuk mempertahankan kompatibilitas, pengguna yang membutuhkan fitur berperforma tinggi yang diaktifkan COEP akan mendapatkan pengalaman yang terdegradasi dalam konteks proxy.

Bagi security researcher, arsitektur proxy mengungkapkan sesuatu yang penting: kebijakan same-origin bukan firewall. Ini adalah model kepercayaan berbasis struktur URL. Web proxy mengeksploitasi fakta bahwa SOP tidak membuat perbedaan intrinsik antara "dua resource ini legitimately same-origin" dan "dua resource ini sudah ditulis ulang URL-nya agar terlihat same-origin." Seluruh stack keamanan browser di atas SOP โ€” CORS, CORB, CORP, COEP, COOP โ€” bisa dilihat sebagai upaya menambahkan pertahanan yang lebih kuat dari identitas origin berbasis URL.

Memahami ini sangat penting bagi siapapun yang mengaudit layanan proxy, merancang kebijakan keamanan browser, atau mengevaluasi postur keamanan nyata aplikasi yang mungkin diakses melalui proxy.


Pertanyaan yang Sering Ditanyakan

Apakah web proxy bisa bypass kebijakan same-origin?

Tidak sepenuhnya. Web proxy bekerja melalui URL rewriting: mengubah semua URL cross-origin menjadi URL same-origin, sehingga pembatasan cross-origin SOP menjadi tidak relevan, bukan di-bypass. Dari perspektif browser, semua konten tampak berasal dari origin proxy sendiri, jadi tidak ada batas lintas asal yang dilintasi. Ini secara arsitektural berbeda dari bypass โ€” SOP masih menegakkan aturannya; proxy hanya merekayasa konten agar aturan tersebut tidak pernah terpicu.

Bagaimana cara kerja CORS mempengaruhi server proxy web?

CORS mempengaruhi server proxy di dua level. Pertama, proxy harus mencegat permintaan preflight OPTIONS dan merespons dengan header CORS yang permisif, karena respons preflight server target sesungguhnya (yang mereferensikan origin target) tidak akan memenuhi pemeriksaan CORS browser untuk origin proxy. Kedua, proxy harus mem-strip header CORS dari respons server target dan menggantinya dengan header yang mereferensikan origin proxy. Pengaturan Access-Control-Allow-Credentials: true, dikombinasikan dengan credentials: 'include' di Service Worker, berarti semua cookie dari origin proxy menyertai setiap permintaan yang diproxy.

Apa itu CORB dan bagaimana dampaknya pada layanan proxy?

Cross-Origin Read Blocking (CORB) adalah pertahanan Chromium yang mencegah respons cross-origin sensitif tertentu (HTML, JSON, XML) masuk ke renderer process ketika dimuat sebagai sub-resource cross-origin. Untuk web proxy yang dikonfigurasi dengan benar, CORB umumnya tidak terpicu karena URL rewriting membuat semua permintaan menjadi same-origin. Namun, CORB bisa menyebabkan masalah selama periode sebelum Service Worker sepenuhnya terdaftar, ketika beberapa permintaan mungkin lolos dari URL rewriting dan dikirim sebagai permintaan cross-origin yang sesungguhnya. CORB diperkenalkan sebagai mitigasi Spectre dan didefinisikan dalam spesifikasi WHATWG Fetch.

Tidak. Cookie HttpOnly diatur oleh server target dan tidak bisa dibaca oleh JavaScript โ€” termasuk JavaScript yang berjalan di Service Worker. Namun, gateway menerima cookie ini ketika meneruskan permintaan atas nama pengguna, karena browser mengirimkannya di header permintaan. Flag HttpOnly mencegah pencurian JavaScript sisi client tapi tidak mencegah server proxy itu sendiri melihat nilai cookie dalam transit. Ini analogis dengan bagaimana HttpOnly melindungi dari XSS tapi bukan dari intersepsi sisi server.

Apakah menggunakan web proxy aman dari perspektif keamanan browser?

Tergantung pada model ancamannya. Dari perspektif browser, semua konten yang dilayani melalui web proxy berjalan di origin proxy, artinya kerentanan dalam JavaScript satu situs yang diproxy berpotensi mengakses data dari sesi situs lain yang diproxy (karena mereka berbagi cookie jar dan storage origin yang sama). Operator proxy juga merupakan pihak tepercaya dengan akses ke semua traffic dalam transit. Untuk mengakses konten non-sensitif di lingkungan yang dibatasi, risikonya biasanya dapat diterima. Untuk sesi terotentikasi dengan layanan sensitif (perbankan, kesehatan, pemerintah), pengguna harus memahami bahwa operator proxy memiliki kemampuan teknis untuk mengamati traffic tersebut, dan hanya boleh menggunakan layanan proxy dengan kebijakan no-log yang dapat diaudit dan praktik keamanan operasional yang kuat.


Artikel ini mencerminkan arsitektur ProxyOrb per awal 2026. Mekanisme keamanan browser berkembang dengan cepat; pembaca dianjurkan untuk memeriksa WHATWG Fetch Standard, spesifikasi W3C Content Security Policy, dan dokumen desain keamanan Chromium untuk informasi terkini.