iframe 임베딩 하네스 (H-C)
고객사 내부 앱은 보통 자기를 iframe 에 못 넣게 막아 둡니다. 프록시가 그 헤더를 다시 써야 임베드가 됩니다 — 그 구현이 실제로 동작하는지 브라우저로 확인합니다.
읽는 법
- onload 로는 판정할 수 없다 — 차단된 프레임도 about:blank 로 load 이벤트가 뜬다. 그래서 프레임이 부모로 보내는 postMessage 를 기다린다. 메시지가 오면 우리 문서가 실제로 렌더된 것이고, 타임아웃이면 브라우저가 막은 것이다.
- 두 열로 읽는다 — 직접 접속에서는 막는 헤더가 그대로 살아 차단되는 것이 정상이고, 프록시 경유에서 통과해야 재작성이 동작하는 것이다. H-A 와 같은 구조다.
- #10 만 기대값이 반대다 — IdP 는 프레임 렌더를 거부하는 것이 맞다(클릭재킹 방지). 거기서 로그인 화면이 뜨면 오히려 위험하다.
- X-Frame-Options 와 CSP 는 처리 방식이 다르다 — 전자는 helmet 이 먼저 심어 두므로 res 에서 직접 지워야 하고, 후자는 값을 덮어써야 한다. 한쪽만 되는 상태가 실제로 있었다.
접속 경로
브라우저가 보는 주소
https://aws-insider-e1e444fd-dfae-480a-b782-5eaa35682f5e.feelanet.ai요청 유도
케이스 10개. 임베드 대상은
/api/lab/frame이고 쿼리로 막는 헤더를 고릅니다.
프록시 쪽
PROXY_FRAME_ANCESTOR_ORIGINS가 비어 있으면 아무도 임베드할 수 없습니다 — 그 경우 #2·#4·#6 이 실패합니다.
아무 제한도 없는 페이지를 임베드한다. 이것이 실패하면 하네스 자체가 고장이다.
/api/lab/frame?token=baseline
가장 흔한 차단 방식. 프록시가 이 헤더를 지워야 임베드된다. 직접 접속에서는 차단되는 것이 정상이다.
★ 프록시가 res.removeHeader('X-Frame-Options') 를 하는 이유가 이 케이스다.
/api/lab/frame?token=xfo-deny&xfo=deny
같은 오리진에서만 허용. 프록시 경유로 보면 페이지와 프레임이 같은 오리진이라 지우지 않아도 통과할 수 있다 — 그래서 이 케이스만으로는 재작성 여부를 못 가른다.
/api/lab/frame?token=xfo-sameorigin&xfo=sameorigin
X-Frame-Options 의 후속 표준. 프록시가 이 값을 다시 쓰지 않으면 차단된다. CSP 는 delete 가 아니라 **값을 새로 세팅**해야 한다는 것이 구현 주석의 요지다.
★ X-Frame-Options 는 res 에서 직접 지워야 하고(helmet 이 먼저 심어 둔다), CSP 는 값을 덮어써야 한다. 처리 방식이 달라서 한쪽만 되는 상태가 실제로 있었다.
/api/lab/frame?token=csp-none&csp=none
같은 오리진만 허용. 프록시 경유에서 어떻게 다시 쓰이는지 본다.
/api/lab/frame?token=csp-self&csp=self
우리를 명시적으로 배제한 정책. 프록시가 허용 목록으로 덮어써야 임베드된다.
/api/lab/frame?token=csp-foreign&csp=https%3A%2F%2Fexample.com
프록시는 이 헤더로 '프레임 안의 내비게이션' 을 판별해 로그인 리다이렉트 대신 안내 페이지를 준다(prism-proxy.middleware.ts). 중간에서 떨어지면 그 분기가 죽는다.
/api/lab/frame?token=sec-fetch-dest
SameSite=Lax 쿠키는 교차 사이트 프레임 요청에 실리지 않는다. 그래서 세션 쿠키가 SameSite=None; Secure 여야 한다 — B-4 와 같은 뿌리의 문제다. 서버가 본 쿠키를 돌려받아 확인한다(document.cookie 는 HttpOnly 를 못 본다).
SameSite=None 쿠키도 브라우저의 서드파티 쿠키 차단(Safari ITP, Chrome 시크릿) 앞에서는 무력하다. 이 한계는 코드로 못 없앤다.
/api/lab/frame?token=frame-cookie
프레임 안의 프레임. frame-ancestors 는 **조상 전체**를 보므로, 한 단계만 허용하면 중첩에서 막힌다. 임베드 위에 또 임베드하는 구성이 있으면 여기서 드러난다.
/api/lab/frame?token=nested-outer
IdP 는 프레임 렌더를 거부한다(클릭재킹 방지). **차단되는 것이 정상**이고, 그래서 프록시가 프레임 안에서는 302 대신 안내 페이지를 준다. 여기서 로그인 화면이 뜨면 오히려 IdP 설정이 위험한 것이다.
★ 이 케이스는 **차단되어야 통과**다. 기대값이 반대인 유일한 케이스.
/api/saml/login?returnTo=/lab/iframe
띄운 프레임들
차단된 것은 빈 칸으로 남습니다