여러 도메인에서 원활한 컨텍스트 내 인증을 제공하기 위해 조직에서는 iframe 내에 로그인 페이지를 삽입하는 경우가 많습니다. 하지만 서드 파티 프레임 내에서 인증 컨텍스트를 로드하면 사용자가 클릭재킹 (UI 리드레싱) 및 무단 사용자 인증 정보 생성과 같은 심각한 위협에 노출됩니다. 이러한 위험을 완화하기 위해 브라우저는 기본적으로 교차 출처 iframe에서 WebAuthn을 사용 중지합니다. 이 제한을 안전하게 해제하려면 활성 심층 방어 프로토콜이 필요합니다.
위협 모델 식별
하위 프레임 내에서 패스키 (WebAuthn)를 사용 설정하기 전에 방어해야 하는 악용 시나리오를 이해하세요.
- 숨겨진 iframe 삽입을 사용한 추적: 공격자가 신뢰할 수 있는 사이트의 광고나 위젯을 사용하여 자체 도메인에서 WebAuthn 프롬프트를 트리거하여 사용자가 컨텍스트를 보지 않고 패스키를 승인하도록 속입니다. 이렇게 하면 사용자의 ID가 공격자가 관리하는 계정에 연결되어 데이터를 수집합니다.
- 시각적 오버레이 및 클릭재킹 (UI 리드레싱): 악성 상위 페이지가 표준 CSS를 사용하여 인증 iframe을 보이지 않게 렌더링하고 인증 흐름을 트리거하는 클릭을 훔치기 위해 가짜 UI 요소를 오버레이합니다. 사용자가 실수로 프롬프트를 완료하면 세션 하이재킹이나 강제적인 승인되지 않은 작업이 발생할 수 있습니다.
이러한 위협에 대응하려면 다음 권장사항을 따르세요.
최상위 문서 (상단 프레임)의 경우:
삽입된 문서 (iframe)의 경우:
두 문서 모두 다음을 충족해야 합니다.
권한 정책을 사용하여 위임 사용 설정
브라우저는 기본적으로 교차 출처 iframe에서 WebAuthn에 대한 액세스를 차단합니다. 권한 정책은 최상위 문서가 이러한 강력한 기능을 신뢰할 수 있는 특정 서드 파티 출처에 명시적으로 위임할 수 있는 통합 웹 플랫폼 메커니즘입니다.
기능 토큰
WebAuthn은 다음과 같은 두 가지 토큰을 사용합니다.
publickey-credentials-get: 패스키 로그인 흐름(navigator.credentials.get())에 대한 승인을 부여합니다.publickey-credentials-create: 패스키 등록 흐름 (navigator.credentials.create())에 대한 승인을 부여합니다.
사용 설정 요구사항
이러한 기능을 사용 설정하려면 상위 서버 응답과 클라이언트 측 마크업이 모두 정렬되어야 합니다.
- Permissions-policy HTTP 응답 헤더 (상위 서버 사이트): 상위 페이지는 구조화된 필드 문법을 사용하여 HTTP 응답 헤더에 허용된 출처를 선언해야 합니다.
Permissions-Policy: publickey-credentials-get=(self "https://embedded-auth.example.com")
권한 정책: publickey-credentials-get 호환성:
권한 정책: publickey-credentials-create 호환성:
- HTML
allow속성: HTML 마크업에서<iframe>요소는 기능을 사용 설정한다고도 선언해야 합니다.
<iframe src="https://embedded-auth.example.com?nonce=deadbeef12345678&client=https%3A%2F%2Fembedded-auth.example.com" allow="publickey-credentials-get"></iframe>
iframe allow="publickey-credentials-get" 호환성:
Browser Support
iframe allow="publickey-credentials-create" 호환성:
Browser Support
파티셔닝된 서드 파티 쿠키 사용 설정
신뢰할 수 있는 인증 흐름을 보장하려면 삽입된 교차 출처 iframe 내에서 세션을 설정하고 유지해야 합니다. 최신 브라우저가 엄격한 서드 파티 쿠키 제한으로 전환됨에 따라 표준 지속성 메커니즘이 기본적으로 차단되는 경우가 많으며 액세스 권한을 얻기 위해 Storage Access API를 호출해야 할 수 있습니다.
이러한 장애물을 완화하려면 SameSite:
None, Secure, Partitioned 속성을 사용하여 세션 쿠키를 구성하세요. 이 통합 플랫폼 메커니즘은 브라우저 수준 개인 정보 보호 설정을 준수하면서 iframe 내에서 지속적인 상태를 보장합니다.
SameSite: None 설정
SameSite:
None는 쿠키를 크로스 사이트 액세스용으로 명시적으로 표시하여 iframe과 같은 서드 파티 컨텍스트에서 이루어진 요청과 함께 전송될 수 있도록 합니다. 이 속성은 쿠키가 교차 출처 시나리오에서 작동하기 위한 필수 요건이지만 최신 브라우저에서 허용되려면 Secure 속성과 결합해야 합니다.
Partitioned 설정
Partitioned 속성은 쿠키를 CHIPS (Cookies Having Independent Partitioned State)에 선택하여 쿠키가 각 최상위 사이트별로 별도로 저장되도록 합니다. 이렇게 하면 쿠키가 특정 서드 파티 iframe 컨텍스트 내에서 액세스 가능하게 유지되어 크로스 사이트 추적을 사용 설정하지 않고도 지속적인 세션 상태를 사용할 수 있습니다. 사용자는 다른 사이트의 각 삽입에 대해 다시 로그인해야 합니다.
콘텐츠 보안 정책으로 엔드포인트 보호
권한 정책은 iframe에서 WebAuthn을 실행할 수 있는지를 결정하는 반면 콘텐츠 보안 정책 (CSP)은 iframe을 호스팅할 수 있는 사용자를 결정합니다.
인증 엔드포인트의 경우 승인된 파트너 사이트 또는 자체 속성만 로그인 하위 프레임을 로드할 수 있도록 하여 UI를 로드하기 전에 승인되지 않은 클릭재킹 시도를 차단하는 것이 중요합니다.
frame-ancestors 사용
frame-ancestors 지시어는 사이트를 삽입할 수 있는 유효한 상위 페이지를 정의합니다. 이 지시문에 도메인을 추가하면 로그인 하위 프레임을 삽입할 수 있는 도메인을 허용할 수 있습니다.
Content-Security-Policy: frame-ancestors 'self' https://parent-site.example.com;
콘텐츠 보안 정책: frame-ancestors 호환성:
X-Frame-Options 설정
기존 X-Frame-Options 헤더는 유사한 기능을 지원하지만 바이너리 옵션 (DENY 또는 SAMEORIGIN)만 지원합니다. 브라우저가 CSP를 지원하지 않는 경우 CSP frame-ancestors 및 X-Frame-Options: DENY를 모두 설정하세요. CSP는 지원되는 경우 항상 우선순위가 지정됩니다.
X-Frame-Options: DENY
X-Frame-Options 호환성:
서버 측에서 신뢰하되 검증
브라우저의 클라이언트 측 검사에서는 의도와 권한을 평가하지만 서버가 신뢰의 최종 중재자입니다. 신뢰 당사자 (RP) 서버에서 응답을 확인하여 컨텍스트가 유효하고 서명되었는지 확인합니다.
클라이언트 데이터 페이로드
WebAuthn 클라이언트 데이터에는 iframe 내에서 이루어진 요청의 컨텍스트를 확인할 수 있도록 특별히 설계된 매개변수가 포함됩니다.
crossOrigin(불리언): WebAuthn API가 교차 출처 iframe 내에서 호출되었는지 여부를 나타냅니다. 아키텍처가 iframe을 사용하는 경우 서버에서 이 플래그가true인지 강제해야 합니다.topOrigin(문자열): 최상위 탐색 컨텍스트의 출처 (브라우저의 주소 표시줄에 표시되는 항목)입니다. 서버는 알려진 승인된 상위 출처 목록에 대해 이를 확인해야 합니다.
확인 체크리스트
서버에서 인증기 응답을 확인하려면 다음 단계를 실행하세요.
- 인증자 응답에서 서명된
collectedClientData를 파싱하고 디코딩합니다. type이 시상식 (webauthn.get또는webauthn.create)과 일치하는지 확인합니다.- 사용자 존재 및 서명을 확인합니다.
- 요청이 iframe 구조에서 발생한 경우 다음을 확인하세요.
crossOrigin === true를 적용합니다.topOrigin가 승인된 상위 출처 목록과 일치하도록 강제합니다.
postMessage()를 사용하여 세션을 안전하게 설정
세션을 안정적으로 설정하려면 iframe이 postMessage()를 사용하여 인증 토큰을 상위 페이지로 다시 전달하여 상위 페이지가 자체 퍼스트 파티 맥락에서 세션 상태를 관리하도록 해야 합니다.
안전한 워크플로
보안 세션을 설정하려면 다음 워크플로를 따르세요.
- iframe
srcURL에nonce및origin쿼리 파라미터가 포함되어 있는지 확인합니다.nonce에 임의의 값을 사용합니다.nonce는 iframe에서 수신한 인증 토큰이 상위 페이지에서 시작한 특정 세션과 적법하게 일치하는지 확인하는 보안 확인 토큰 역할을 합니다.origin에 상위 프레임 도메인을 사용합니다.origin매개변수는 상위 페이지의 출처를 지정하여 iframe이 삽입된 승인된 컨텍스트를 안전하게 식별할 수 있도록 합니다.
- iframe이 자체 서버로 WebAuthn 인증을 완료합니다.
iframe 서버는
nonce를 포함하는 JWT와 같은 토큰을 발급하고 상위 페이지로 전달합니다.// Extract nonce and origin from the URL params const urlParams = new URLSearchParams(window.location.search); const nonce = urlParams.get('nonce'); const origin = urlParams.get('origin'); if (!nonce || !origin) { alert('Nonce or origin is missing in the URL'); return; } // Create a JWT const response = await post('/createToken', { nonce, origin }); const token = response.token; // Post the JWT to the parent frame window.parent.postMessage({ token }, origin);상위 페이지는
message이벤트를 수신 대기하고, 발신자 출처를 검증하고, 토큰을 확인합니다.window.addEventListener("message", (event) => { if (event.origin !== "https://embedded-auth.example.com") return; // Verify the received JWT const result = await post('/verifyIdToken', { token: event.data.token, origin: provider.origin, }); });JWT가 성공적으로 확인되면 상위 페이지에서 세션을 유지합니다.
보낸 사람과 받는 사람은 모두 보안 책임을 공유합니다.
- 발신자 (iframe): 메시지를 보낼 때는 항상 엄격한 타겟 출처를 지정하세요 (
"*"는 사용하지 마세요). - 수신기 (상위): 메시지를 수신할 때 항상
event.origin를 확인하여 출처 스푸핑을 방지합니다.
결론
안전한 iframe 사용은 사용 설정에 관한 권한 정책, 제한에 관한 CSP, 세션 지속성을 위한 파티셔닝된 서드 파티 쿠키, 클라이언트 컨텍스트의 서버 측 확인, postMessage()를 사용한 컨텍스트 인식 세션 핸드오프에 달려 있습니다.
관련 주제에 대해 자세히 알아보려면 Google Chrome 개발자 블로그를 팔로우하고 Chrome 개발자 ID 문서에서 추가 리소스를 살펴보세요.