ProxyOrb를 만들면서 설계 결정을 내릴 때마다 근본적인 역설과 마주쳤습니다. 웹 프록시는 브라우저가 제3자 콘텐츠를 동일 출처 콘텐츠로 믿게 만드는 방식으로 작동합니다. 이는 정의상 브라우저의 핵심 보안 모델을 속이는 행위입니다. 그런데 현대 브라우저들은 지난 15년간 정확히 이런 오리진 혼동을 막기 위한 방어 레이어를 꾸준히 쌓아 왔습니다.
이 글은 그 긴장 관계를 처음 원리부터 파헤칩니다. 웹 프록시가 동일 출처 정책과 실제로 어떻게 상호작용하는지를 개념 수준이 아니라, HTTP 헤더, Chromium 소스 코드, 그리고 프로덕션 엔지니어링의 트레이드오프 수준에서 이해하고 싶은 보안 연구자, 침투 테스터, 브라우저 보안 엔지니어를 위해 작성했습니다.
SOP 기초부터 URL 재작성, CORS, CORB/CORP, COEP/COOP, Service Worker, iframe, 그리고 프록시 운영자와 사용자 모두에게 미치는 보안 함의까지 다룹니다.
1. 동일 출처 정책의 기초
동일 출처 정책(SOP)은 스킴 + 호스트 + 포트라는 세 가지 튜플로 정의됩니다. 두 URL이 동일 출처이려면 세 가지 구성 요소가 정확히 일치해야 합니다. https://example.com:443과 http://example.com:80은 같은 서버를 가리키더라도 크로스 오리진입니다.
SOP가 실제로 무엇을 막는지, 무엇을 허용하는지에 대해 자주 오해하는 부분이 있습니다. SOP는 다음 항목을 막지 않습니다:
- 크로스 오리진 이미지 로딩 (
<img src>) - 크로스 오리진 스크립트 로딩 (
<script src>) - 크로스 오리진 스타일시트 로딩 (
<link rel="stylesheet">) - 크로스 오리진 iframe 임베딩 (단, 임베딩된 문서의 내용은 격리됨)
- 크로스 오리진 폼 전송 (
<form action>)
SOP가 실제로 막는 것은 fetch()나 XMLHttpRequest를 통해 만들어진 크로스 오리진 요청의 응답을 읽는 행위입니다. 요청 자체는 나가고 — 네트워크 왕복도 일어나지만 — 응답 본문과 헤더는 다른 오리진에서 실행 중인 JavaScript에 전달되지 않습니다.
이 구분이 웹 프록시에서 엄청나게 중요합니다. 프록시의 핵심 역할은 두 개의 오리진(프록시 서버와 타깃 서버)을 하나로 합쳐서 크로스 오리진 경계를 없애는 것입니다. 모든 리소스가 https://proxyorb.com에서 오는 것처럼 보이면, 브라우저의 SOP 기반 응답 읽기 제한은 그냥 적용되지 않습니다.
웹 프록시가 활용하는 "합법적 공간"은 URL 재작성입니다. https://example.com/api/data 대신 모든 요청이 https://proxyorb.com/api/data?__pot=aHR0cHM6Ly9leGFtcGxlLmNvbQ==이 됩니다. 브라우저 입장에서는 이게 동일 출처 요청입니다. SOP를 우회한 게 아니라, 모든 콘텐츠의 외관상 오리진을 바꿔서 SOP를 무의미하게 만든 것입니다.
2. ProxyOrb의 URL 재작성 아키텍처
보안 함의를 제대로 이해하려면 인코딩 메커니즘을 알아야 합니다. ProxyOrb는 __pot(proxy origin token)이라는 URL 파라미터를 사용하며, 여기에 Base64로 인코딩된 타깃 오리진이 담깁니다.
__pot 파라미터
__pot 파라미터는 항상 전체 URL이 아니라 타깃의 오리진(스킴 + 호스트, 경로 없음)을 인코딩합니다. 즉, https://example.com/some/deep/path?foo=bar와 https://example.com/other/page는 둘 다 같은 __pot 값인 aHR0cHM6Ly9leGFtcGxlLmNvbQ==(https://example.com의 Base64 인코딩)을 생성합니다. 실제 경로와 쿼리 스트링은 프록시 URL의 경로와 쿼리 스트링에 그대로 보존됩니다.
사용자가 https://proxyorb.com/?__pot=aHR0cHM6Ly9leGFtcGxlLmNvbQ==로 접속하면 게이트웨이가 이를 디코딩해서 원래 URL을 재구성합니다:
그런 다음 게이트웨이는 요청을 실제 타깃 서버로 전달하고, Origin 헤더를 재작성해서 업스트림 서버가 프록시 도메인이 아닌 자신의 도메인을 보도록 합니다:
Service Worker를 통한 클라이언트 측 URL 재작성
게이트웨이는 서버 측을 담당합니다. 클라이언트 측 — HTML, JavaScript, CSS 응답에서 URL을 재작성해 모든 하위 요청이 계속 프록시를 통하도록 만드는 작업 — 은 Service Worker가 처리합니다.
핵심 변환은 페이지 콘텐츠에서 발견된 모든 URL을 프록시 형식으로 바꿉니다:
예를 들어, 프록시 중인 페이지 내에서 참조된 https://cdn.example.com/bundle.js는 https://proxyorb.com/bundle.js?__pot=aHR0cHM6Ly9jZG4uZXhhbXBsZS5jb20=이 됩니다.
이 재작성은 포괄적입니다. fetch(), XMLHttpRequest, <script src>, <img src>, WebSocket 연결, <link> 태그를 모두 커버합니다. 페이지의 모든 URL이 프록시 오리진을 가리키면, 브라우저는 절대로 크로스 오리진 요청을 보내지 않습니다 — 구조적으로 모든 요청이 동일 출처이기 때문입니다.
전체 탐색 없이 __pot 복구하기
프록시된 페이지 내부에서 시작됐지만 __pot 파라미터가 없는 요청에서 미묘한 엣지 케이스가 발생합니다. 예를 들어, Service Worker가 URL을 재작성하기 전에 실행되는 상대 경로 fetch('/api/data')나 URL 재작성기를 우회한 동적 주입 스크립트가 보내는 요청이 그런 경우입니다.
Service Worker는 계단식 조회를 통해 누락된 토큰을 복구합니다:
게이트웨이에도 병렬 복구 경로가 있습니다. __pot 없이 요청이 도착하더라도 Referer 헤더가 __pot을 포함한 동일 오리진 URL을 가리키면, 게이트웨이가 리퍼러에서 토큰을 추출해 현재 요청에 첨부합니다. 이는 게이트웨이가 요청을 받기 전에 페이지 JavaScript가 토큰을 제거한 탐색 시나리오를 처리합니다.
3. CORS: 명시적 크로스 오리진 권한 시스템
CORS(Cross-Origin Resource Sharing)는 서버가 특정 응답 헤더를 보내 크로스 오리진 접근을 명시적으로 허용할 수 있게 설계되었습니다. 프록시 관점에서 CORS는 두 가지 뚜렷한 문제를 만듭니다.
문제 1: CORS 프리플라이트 인터셉션
페이지에서 실행 중인 JavaScript가 비단순 헤더(예: Authorization, Content-Type: application/json)로 fetch() 요청을 보낼 때, 브라우저는 먼저 OPTIONS 프리플라이트 요청을 보냅니다. 타깃 서버의 프리플라이트 응답에 허용적인 CORS 헤더가 없으면 실제 요청은 차단됩니다.
ProxyOrb 아키텍처에서 Service Worker는 모든 OPTIONS 요청을 인터셉트하고 — 게이트웨이에 도달하기도 전에 — 합성 응답을 반환해서 실제 요청의 차단을 해제합니다:
게이트웨이 레벨에서는 모든 프록시된 응답에 동등한 CORS 헤더를 추가합니다:
문제 2: 자격 증명 포함 요청
Access-Control-Allow-Credentials: true와 와일드카드가 아닌 Access-Control-Allow-Origin의 조합은 중요한 의미를 가집니다. CORS는 자격 증명이 포함될 때 와일드카드(*)가 아닌 명시적인 오리진 값을 요구합니다. Service Worker는 모든 외부 요청을 credentials: 'include'로 보내기 때문에, 게이트웨이는 와일드카드 대신 정확한 요청 오리진을 돌려줘야 합니다.
이는 proxyorb.com 아래에 저장된 모든 쿠키 — 사용자가 프록시를 통해 방문한 모든 타깃 사이트에서 쌓인 쿠키 — 가 모든 프록시 요청에 함께 전송된다는 뜻입니다. 이는 의도된 동작(로그인된 사이트의 세션 상태 유지)이지만, 8절에서 논의하는 중요한 웹 프록시 보안 고려 사항이기도 합니다.
CORS 헤더 교체 패턴
프록시된 응답에는 브라우저 관점에서 잘못된 — 프록시 오리진이 아닌 타깃 오리진을 참조하는 — CORS 헤더가 포함될 수 있습니다. Service Worker는 이를 제거하고 교체합니다:
4. CORB와 CORP: Chromium의 더 강력한 방어
CORS는 서버의 명시적인 옵트인에 의존합니다. Chromium은 CORS 설정과 무관하게 기본으로 활성화되는 두 가지 메커니즘을 추가했습니다.
Cross-Origin Read Blocking (CORB)
CORB는 Spectre 완화책의 일환으로 Chrome 67(2018년)에 도입되었습니다. 핵심 인사이트: 크로스 오리진 응답 본문이 JavaScript에 의해 읽히지 않더라도, 그것이 렌더러 프로세스에 의해 페치되고 디코딩된다는 사실 자체가 그 프로세스의 주소 공간에 해당 데이터가 존재한다는 뜻입니다. 그러면 Spectre 계열 공격이 사이드 채널로 이를 추출할 수 있습니다.
CORB는 특정 크로스 오리진 응답이 렌더러 프로세스에 아예 들어오지 못하게 막습니다. 구체적으로, <script> 태그나 <img> 태그가 크로스 오리진 응답을 페치하고 해당 응답의 Content-Type이 text/html, text/xml, application/json이면, Chromium은 본문을 검사(CORB 명세에 정의된 MIME 타입 스니퍼 사용)하고, 타입이 일치하면 렌더러가 응답을 받기 전에 빈 응답으로 교체합니다.
웹 프록시에서 요청이 실제로 크로스 오리진이었다면 CORB는 치명적이었을 것입니다. <script> 태그로 페치한 application/json을 반환하는 API 엔드포인트가 조용히 빈 값을 돌려줄 테니까요. 하지만 ProxyOrb는 모든 URL을 동일 출처로 재작성하기 때문에 CORB의 크로스 오리진 조건이 절대 트리거되지 않습니다 — 브라우저 입장에서 모든 응답이 proxyorb.com에서 오기 때문에 크로스 오리진 JSON 응답을 보지 않습니다.
CORB가 중요한 유일한 케이스는 Service Worker가 완전히 등록되어 요청을 인터셉트하기 전인 전환 기간 중입니다. 그 윈도우에서 URL 재작성을 벗어난 요청이 있으면 CORB가 차단할 수 있습니다. 이 레이스 컨디션 때문에 ProxyOrb는 메인 스레드 인터셉터 레이어도 유지합니다. 이 레이어는 페이지 JavaScript가 실행되기 전에 동기적으로 XMLHttpRequest, fetch, DOM 속성 setter를 패치해서 Service Worker 시작 중 폴백을 제공합니다.
CORB는 Opaque Response Blocking (ORB)으로 부분적으로 대체되고 있으며, Chromium이 채택 중입니다. ORB는 Spectre 보호를 유지하면서 오탐을 줄이기 위해 CORB 규칙을 개선합니다. 프록시 호환성 함의는 비슷합니다.
Cross-Origin Resource Policy (CORP)
CORP는 Fetch 명세에 정의되어 있으며, 서버가 자신의 리소스를 동일 오리진 또는 동일 사이트 컨텍스트에서만 로드할 수 있다고 선언하게 해줍니다:
Chromium이 크로스 오리진 하위 리소스 요청에서 이 헤더를 만나면 응답을 완전히 차단합니다. 이는 CORB보다 더 공격적입니다 — 콘텐츠 타입과 무관하게 적용되며 MIME 스니핑으로 우회할 수 없습니다.
다시 말하지만, ProxyOrb의 URL 재작성이 브라우저 관점에서 모든 요청을 동일 출처로 만들기 때문에 타깃 서버의 CORP 헤더는 차단을 트리거하지 않습니다. 게이트웨이도 URL 재작성을 거치지 않고 들어오는 엣지 케이스를 처리하기 위해 응답에서 이 헤더를 방어적으로 제거합니다.
CORP와 관련해 프록시 아키텍처가 오히려 호환성에 도움이 되는 흥미로운 케이스가 있습니다. https://api.example.com과 https://www.example.com이 둘 다 프록시되고 있다면, 둘 다 같은 프록시 오리진에 매핑되므로 한쪽에서 다른 쪽으로의 fetch가 이제 진짜 동일 출처입니다 — 서로 간의 CORP 제한이 더 이상 적용되지 않습니다.
5. COEP와 COOP: 크로스 오리진 격리
Chrome 92(2021년)부터 SharedArrayBuffer 접근 — 그리고 특정 성능 API에 사용되는 고해상도 타이머 — 은 크로스 오리진 격리를 옵트인한 페이지로 제한되었습니다. 이 옵트인에는 두 가지 응답 헤더가 함께 작동해야 합니다.
Cross-Origin-Embedder-Policy (COEP)
페이지가 이 헤더를 보내면, 브라우저는 해당 페이지가 로드하는 모든 하위 리소스가 다음 중 하나를 만족하도록 강제합니다:
- 동일 출처이거나, 또는
Cross-Origin-Resource-Policy: cross-origin을 명시적으로 보내거나, 또는- 자격 증명 포함 fetch에 대해 허용적인 CORS 응답을 가지거나
웹 프록시에서의 문제: 타깃 사이트가 메인 문서에 COEP: require-corp를 보내고, 그 문서가 헤더가 보존된 채로 프록시를 통해 서빙되면, 브라우저는 이제 그 페이지가 로드하는 모든 하위 리소스도 옵트인하기를 요구합니다. 그렇게 하지 않는 리소스는 — 대부분이 그럴 것입니다 — 네트워크 에러를 발생시킵니다.
Cross-Origin-Opener-Policy (COOP)
COOP는 페이지가 크로스 오리진 페이지와 브라우징 컨텍스트 그룹을 공유할 수 있는지를 제어합니다. same-origin으로 설정하면, 크로스 오리진 탐색 시 새 브라우징 컨텍스트 그룹이 열리면서 window.opener 참조와 페이지 및 크로스 오리진 오프너 간의 postMessage 채널이 끊어집니다.
프록시에서 COOP는 COEP만큼 즉각적으로 파괴적이지는 않지만, 크로스 오리진 postMessage 흐름(OAuth 팝업 흐름이 가장 흔한 예)에 의존하는 사이트를 여전히 망가뜨립니다.
프록시 운영자의 딜레마
ProxyOrb에서 가장 어려운 트레이드오프입니다:
옵션 A: 응답에서 COEP와 COOP를 제거한다.
- 장점: 하위 리소스 로딩이 정상적으로 작동하고, 프록시된 페이지가 이 제한을 적용하지 않는다.
- 단점: 타깃 사이트가 의도적으로 설정한 보안 헤더를 제거하는 것이다. 사이트가 Spectre 계열 공격으로부터 민감한 데이터를 보호하기 위해 크로스 오리진 격리를 사용하고 있었다면, 이 헤더들을 제거하면 그 위험이 다시 노출된다.
옵션 B: COEP와 COOP를 보존한다.
- 장점: 타깃 사이트의 보안 의도가 존중된다.
- 단점:
CORP: cross-origin을 명시적으로 설정하지 않은 모든 하위 리소스 로딩이 실패해서 대부분의 복잡한 웹 애플리케이션이 망가진다.
ProxyOrb의 현재 전략은 옵션 A입니다. 게이트웨이가 응답에서 Cross-Origin-Embedder-Policy와 Cross-Origin-Opener-Policy를 제거합니다. 이는 사이트 호환성을 극대화합니다. 보안 트레이드오프는 의도적으로 선택한 것입니다. 웹 프록시 사용자는 의도된 배포 환경과 다른 환경에서 콘텐츠를 실행하고 있다는 점을 받아들이는 것입니다.
각각의 새로운 브라우저 보안 메커니즘은 일정한 패턴을 따릅니다. 옵트인으로 도입되고(사이트가 원하면 헤더를 보낼 수 있음), 점차 새 API의 기본이 되며, 결국 강제 적용이 검토됩니다. COEP가 이 경로를 걸었습니다. Chrome 83에서 선택적이다가, Chrome 91에서 SharedArrayBuffer의 필수 요건이 됐습니다. 타사 콘텐츠를 조율 없이 임베딩하는 사이트들은 콘텐츠가 망가지는 것을 발견했습니다. 웹 프록시는 정의상 제3자 콘텐츠를 중개하기 때문에 이 문제를 더 심화시킵니다.
브라우저 보안 커뮤니티도 이 문제를 인식하고 있습니다. 현재 진행 중인 Document-Isolation-Policy 제안은 크로스 오리진 격리 요구 사항에서 프로세스 격리를 분리하는 것을 목표로 하며, 모든 하위 리소스가 옵트인할 필요 없이 Spectre 완화를 얻을 수 있게 될 가능성이 있습니다. 이것이 출시되면 격리 헤더와의 프록시 호환성이 개선될 수 있습니다.
6. Service Worker: 브라우저 측 신뢰 레이어
Service Worker는 단순한 최적화가 아닙니다 — ProxyOrb의 보안 모델에 구조적으로 필수적입니다.
등록 스코프는 오리진에 귀속됨
Service Worker는 항상 등록 페이지의 오리진 내에 있는 scope로 등록됩니다. ProxyOrb가 Service Worker를 등록할 때 스코프는 https://proxyorb.com/이며, 이는 해당 오리진 아래의 모든 페이지에서 오는 모든 fetch를 인터셉트한다는 의미입니다.
URL 재작성이 동일 출처로 작동하는 근본적인 이유가 여기에 있습니다. SW가 클라이언트를 제어하면, 해당 클라이언트에서 오는 모든 네트워크 요청이 — 페이지의 JavaScript가 어떤 URL을 fetch하려 하든 — 먼저 Service Worker를 통과합니다.
인터셉션 파이프라인
Service Worker가 요청을 인터셉트하면 여러 결정 단계를 거칩니다:
투명한 헤더 포워딩
미묘한 도전이 하나 있습니다. 브라우저는 Fetch API를 통해 특정 "금지된" 요청 헤더(Host, Origin, Referer 등)를 JavaScript가 설정하지 못하도록 제한합니다. Service Worker는 제한된 헤더를 단일 커스텀 통과 헤더로 인코딩해서 이를 우회합니다. 게이트웨이는 타깃 서버로 전달하기 전에 이를 디코딩하고 적용합니다:
신뢰할 수 있는 중개자로서 Service Worker의 보안 함의
보안 관점에서 Service Worker는 특권적인 위치를 차지합니다. 스코프 내의 모든 페이지에서 오는 모든 요청을 검사, 수정, 위조할 수 있습니다. 합법적인 프록시 사용에서는 이것이 바로 핵심 목적입니다. 악의적인 프록시에서는 극히 강력한 공격 표면이 될 것입니다.
Service Worker 스크립트 자체의 신뢰성이 매우 중요한 이유가 바로 이것입니다. ProxyOrb는 인터셉터 스크립트를 엄격한 캐시 제어와 함께 HTTPS를 통해 자체 오리진에서 서빙합니다. 공격자가 수정된 Service Worker를 주입할 수 있다면, 영향을 받는 사용자의 모든 트래픽을 인터셉트할 수 있습니다 — 프록시 트래픽뿐만 아니라 해당 오리진 아래의 페이지에서 오는 모든 요청까지.
7. iframe: 프레임 조상 문제
iframe은 일반 하위 리소스와는 다른 독자적인 도전을 제기합니다. 자체 탐색, 자체 SOP 경계, 자체 임베딩 제한을 가진 중첩된 브라우징 컨텍스트를 포함하기 때문입니다.
X-Frame-Options와 frame-ancestors
페이지가 iframe에 임베딩되는 것을 막는 두 가지 메커니즘이 있습니다:
레거시: X-Frame-Options: DENY 또는 X-Frame-Options: SAMEORIGIN
현대적: Content-Security-Policy: frame-ancestors 'none' 또는 frame-ancestors 'self'
게이트웨이가 이 중 하나를 보내는 타깃 페이지를 프록시하면, 해당 페이지를 프록시 오리진 아래의 iframe에 임베딩할 수 없게 됩니다. X-Frame-Options: SAMEORIGIN은 타깃 오리진(example.com)을 참조하는데, 프록시는 페이지를 proxyorb.com에서 서빙하므로 브라우저의 동일 출처 확인이 실패합니다.
프록시는 프록시된 응답에서 이 헤더들을 제거하고 CSP를 허용적인 버전으로 교체해야 합니다:
iframe 인터셉션과 스크립트 주입
임베딩된 iframe은 두 번째 문제를 제기합니다. 콘텐츠는 프록시에서 로드되지만, iframe의 브라우징 컨텍스트에는 자동으로 Service Worker나 메인 스레드 인터셉터가 활성화되지 않습니다. 프록시된 페이지가 <iframe src="https://widget.example.com/...">을 생성하면, 그 iframe URL도 프록시 형식으로 재작성되어야 하고 프록시의 인터셉터 스크립트가 iframe 문서에 주입되어야 합니다.
iframe 인터셉터는 두 가지 레벨에서 작동합니다:
레벨 1 — 프로토타입 패칭 (프로그래밍 방식의 iframe 생성을 포착):
레벨 2 — MutationObserver 폴백 (DOM에 삽입된 iframe을 포착):
sandbox 속성 문제
HTML sandbox 속성은 iframe이 할 수 있는 것을 제한합니다. sandbox="allow-scripts allow-same-origin"은 스크립트 실행, 폼 제출, 크로스 오리진 접근 등을 제어합니다. 프록시 주입이 작동하려면 iframe이 스크립트를 실행하고 부모의 프록시 컨텍스트에 접근할 수 있어야 합니다.
allow-same-origin 토큰은 특히 미묘합니다. allow-scripts와 함께 존재하면 샌드박스의 오리진 격리를 무력화합니다 — iframe이 임베딩 페이지의 오리진으로 실행됩니다. 없으면, iframe은 고유한 불투명 오리진을 갖게 되어 프록시 스크립트 주입이 완전히 불가능해집니다.
ProxyOrb의 현재 sandbox 속성 처리 방식은 프록시 스크립트를 주입하기 전에 sandbox 속성을 완전히 제거하는 것입니다:
이는 중요한 보안 트레이드오프입니다. 샌드박싱은 원래 사이트가 임베딩된 콘텐츠의 기능을 제한하기 위해 의도적으로 배치한 것입니다. 이를 제거하면 해당 콘텐츠가 할 수 있는 것이 확장됩니다. 최종 사용자에게는 보이지 않지만 프록시 세션의 보안 태세에 실질적으로 영향을 미치는 종류의 결정입니다.
8. 프록시 운영자를 위한 보안 함의
공격 표면 전경
사용자가 ProxyOrb를 통해 브라우징할 때 여러 범주의 민감한 데이터가 프록시 오리진을 통해 흐릅니다:
세션 쿠키: 모든 타깃 사이트가 proxyorb.com을 통해 프록시되므로 쿠키는 해당 오리진 아래에 저장됩니다. 사용자의 은행, 이메일, 소셜 미디어의 인증된 세션이 모두 단일 도메인 아래의 쿠키입니다. Service Worker의 credentials: 'include'는 이 쿠키들이 모든 프록시 요청에 동반된다는 의미입니다.
Referer 헤더: 업스트림 서버로 전송되는 Referer 헤더는 사용자가 어떤 페이지를 보고 있었는지 드러냅니다. 프록시는 타깃 서버로 전달하기 전에 referer 값에서 자체 도메인을 신중하게 제거합니다. 요청이 https://proxyorb.com/some/path?__pot=...에서 시작된다면, 외부 Referer 헤더는 원래 타깃 URL(https://example.com/some/path)로 재구성됩니다 — 프록시 도메인은 절대로 업스트림 서버에 유출되지 않습니다.
JavaScript 실행 컨텍스트: 프록시를 통해 서빙된 모든 JavaScript 파일은 수정(URL 재작성)되고 프록시 오리진에서 실행됩니다. ProxyOrb를 통해 프록시된 evil.example.com의 악의적인 스크립트는 proxyorb.com 오리진에서 실행되며, 사용자가 프록시를 통해 접근한 모든 다른 타깃 사이트의 데이터가 있는 로컬 스토리지, 쿠키, IndexedDB에 완전히 접근할 수 있습니다.
악의적인 프록시 위협 모델
교육적 목적으로, 악의적인 프록시가 할 수 있는 것과 ProxyOrb가 의도적으로 하지 않는 것을 명시적으로 언급할 가치가 있습니다:
-
자격 증명 수집: 악의적인 프록시는 게이트웨이를 통과하는 모든 요청 본문(비밀번호와 폼 데이터 포함)을 기록할 수 있습니다.
-
세션 하이재킹: 모든 타깃 사이트 쿠키가 프록시 도메인 아래에 저장되므로, 악의적인 프록시 운영자는 게이트웨이를 통해 서버 측에서 해당 쿠키에 접근할 수 있습니다.
-
콘텐츠 주입: 프록시는 필연적으로 페이지 콘텐츠를 수정합니다(Service Worker 주입 및 URL 재작성을 위해). 악의적인 프록시는 임의의 JavaScript — 키로거, 크립토 마이너, 광고 사기 스크립트 — 를 사용자에게 보이지 않게 주입할 수 있습니다.
-
SSL 스트리핑: 프록시가 게이트웨이-사용자 구간에서 HTTPS 연결을 HTTP로 다운그레이드하면 모든 트래픽이 평문이 됩니다.
ProxyOrb는 엔드투엔드 HTTPS로 운영되며 요청 본문을 기록하지 않습니다. 모든 웹 프록시 운영자는 이런 기술적 능력을 가지고 있습니다. 그래서 신뢰할 수 있는 프록시 운영자를 선택하는 것이 신뢰할 수 있는 VPN 제공업체를 선택하는 것만큼 중요합니다.
혼합 콘텐츠
현대 브라우저는 혼합 콘텐츠 차단을 적용합니다. HTTPS 페이지는 HTTP 하위 리소스를 로드할 수 없습니다. ProxyOrb는 타깃 URL이 HTTP를 사용하더라도 게이트웨이에서 모든 외부 연결에 HTTPS를 강제해서 이를 처리합니다. CSP 오버라이드에는 upgrade-insecure-requests가 포함되어 브라우저가 로드하기 전에 HTTP 하위 리소스 URL을 HTTPS로 업그레이드하도록 지시합니다.
이는 일반적으로 바람직하지만, 의도적으로 HTTP를 통해 리소스를 서빙하는 사이트(레거시 CDN, 로컬호스트 리소스 등)를 망가뜨릴 수 있습니다.
9. 끝없는 군비 경쟁: 결론
ProxyOrb 구축을 시작했을 때 주요 호환성 과제는 CORS와 X-Frame-Options였습니다. 그 이후로 Chromium은 CORB, CORP, COEP, COOP를 출시했고 Document-Isolation-Policy를 개발 중입니다. 방향은 명확합니다. 브라우저는 크로스 오리진 경계 강제에 점점 더 공격적이 되고 있으며, 각 새로운 메커니즘은 프록시 인프라의 적응을 요구합니다.
가장 중요한 임박한 도전은 주요 웹 애플리케이션 전반에 걸친 COEP의 완전한 배포일 가능성이 높습니다. 성능을 위해 SharedArrayBuffer를 사용하는 사이트(영상 편집기, IDE, 협업 도구)는 점점 더 COEP: require-corp를 설정하고 있습니다. ProxyOrb가 호환성을 유지하기 위해 이 헤더를 제거하면서, COEP가 활성화하는 고성능 기능이 필요한 사용자는 프록시 환경에서 해당 기능이 저하되는 것을 발견하게 될 것입니다.
보안 연구자들에게 프록시 아키텍처는 중요한 사실을 드러냅니다. 동일 출처 정책은 방화벽이 아닙니다. URL 구조에 기반한 신뢰 모델입니다. 웹 프록시는 SOP가 "이 두 리소스는 합법적으로 동일 출처다"와 "이 두 리소스는 동일 출처처럼 보이도록 URL이 재작성됐다"를 본질적으로 구별하지 못한다는 사실을 이용합니다. SOP 위의 전체 브라우저 보안 스택 — CORS, CORB, CORP, COEP, COOP — 은 URL 기반 오리진 정체성보다 더 견고한 방어를 추가하려는 시도로 볼 수 있습니다.
이것을 이해하는 것은 프록시 서비스를 감사하거나, 브라우저 보안 정책을 설계하거나, 프록시를 통해 접근될 수 있는 애플리케이션의 실제 보안 태세를 평가하는 모든 사람에게 필수적입니다.
자주 묻는 질문 (FAQ)
웹 프록시는 동일 출처 정책을 우회하는 건가요?
정확히는 아닙니다. 웹 프록시는 URL 재작성으로 작동합니다. 모든 크로스 오리진 URL을 동일 출처 URL로 변환해서 SOP의 크로스 오리진 제한을 우회하는 게 아니라 무의미하게 만드는 것입니다. 브라우저 관점에서 모든 콘텐츠가 프록시 자체 오리진에서 오는 것처럼 보이므로 크로스 오리진 경계가 전혀 넘어지지 않습니다. 이는 구조적으로 우회와 다릅니다 — SOP는 여전히 자신의 규칙을 적용하고 있고, 프록시는 단지 그 규칙들이 절대 트리거되지 않도록 콘텐츠를 설계하는 것입니다.
CORS는 웹 프록시 서버에 어떤 영향을 미치나요?
CORS는 두 가지 레벨에서 프록시 서버에 영향을 미칩니다. 첫째, 프록시는 OPTIONS 프리플라이트 요청을 인터셉트하고 허용적인 CORS 헤더로 응답해야 합니다. 실제 타깃 서버의 프리플라이트 응답(타깃 오리진을 참조함)은 프록시 오리진에 대한 브라우저의 CORS 확인을 만족시키지 못하기 때문입니다. 둘째, 프록시는 타깃 서버 응답의 CORS 헤더를 제거하고 프록시 오리진을 참조하는 헤더로 교체해야 합니다. Service Worker의 credentials: 'include'와 결합된 Access-Control-Allow-Credentials: true 설정은 프록시 오리진의 모든 쿠키가 모든 프록시 요청에 동반됨을 의미합니다.
CORB가 뭔가요? 프록시 서비스에 어떤 영향을 미치나요?
Cross-Origin Read Blocking (CORB)은 특정 민감한 크로스 오리진 응답(HTML, JSON, XML)이 크로스 오리진 하위 리소스로 로드될 때 렌더러 프로세스에 들어오지 못하게 막는 Chromium 방어 메커니즘입니다. 올바르게 구성된 웹 프록시에서는 URL 재작성이 모든 요청을 동일 출처로 만들기 때문에 일반적으로 CORB가 트리거되지 않습니다. 하지만 Service Worker가 완전히 등록되기 전 기간에, 일부 요청이 URL 재작성을 벗어나 진짜 크로스 오리진 요청으로 전송되면 CORB가 문제를 일으킬 수 있습니다. CORB는 Spectre 완화책으로 도입되었으며 WHATWG Fetch 명세에 정의되어 있습니다.
웹 프록시가 HttpOnly 쿠키에 접근할 수 있나요?
없습니다. HttpOnly 쿠키는 타깃 서버가 설정하며 JavaScript로 읽을 수 없습니다 — Service Worker에서 실행되는 JavaScript도 마찬가지입니다. 하지만 게이트웨이는 사용자를 대신해서 요청을 전달할 때 이 쿠키들을 받습니다. 브라우저가 요청 헤더에 쿠키를 포함해서 보내기 때문입니다. HttpOnly 플래그는 클라이언트 측 JavaScript 탈취를 막지만, 프록시 서버 자체가 전송 중 쿠키 값을 보는 것은 막지 않습니다. 이는 HttpOnly가 XSS로부터는 보호하지만 서버 측 인터셉션으로부터는 보호하지 않는 것과 유사합니다.
브라우저 보안 관점에서 웹 프록시 사용은 안전한가요?
위협 모델에 따라 다릅니다. 브라우저 관점에서 웹 프록시를 통해 서빙된 모든 콘텐츠는 프록시 오리진에서 실행됩니다. 즉, 프록시된 한 사이트의 JavaScript 취약점이 잠재적으로 다른 프록시된 사이트의 세션 데이터에 접근할 수 있습니다(같은 오리진의 쿠키 저장소와 스토리지를 공유하므로). 프록시 운영자도 전송 중인 모든 트래픽에 접근할 수 있는 신뢰받는 당사자입니다. 제한된 환경에서 민감하지 않은 콘텐츠에 접근하는 경우에는 위험이 일반적으로 허용 가능합니다. 민감한 서비스(은행, 의료, 정부)의 인증된 세션에서는, 프록시 운영자가 해당 트래픽을 기술적으로 관찰할 수 있다는 점을 이해하고, 감사 가능한 무로그 정책과 강력한 운영 보안 관행을 갖춘 프록시 서비스만을 사용해야 합니다.
이 글은 2026년 초 기준 ProxyOrb의 아키텍처를 반영합니다. 브라우저 보안 메커니즘은 빠르게 진화합니다. 최신 정보는 WHATWG Fetch 표준, W3C Content Security Policy 명세, Chromium 보안 설계 문서를 참고하세요.
