← All issues

[4] FrameLoader inherits empty registrable domain for about:blank popups

Severity: Medium | Component: WebCore FrameLoader | d6c7e00

diff가 수정하는 문제는 어느 first-party 페이지에서든 window.open('about:blank')를 통해 도달할 수 있는 안정적인 third-party cookie blocking bypass입니다. 영향 범위는 memory safety가 아닌 privacy/tracking에 해당하므로 Medium으로 평가합니다.

about:blank popup이 cross-origin 요청을 보낼 때, 해당 popup의 firstPartyForCookiesabout:blank로 설정되어 있었습니다. about:blank의 registrable domain은 빈 문자열이기 때문에, thirdPartyCookieBlockingDecisionForRequest()ThirdPartyCookieBlockingDecision::None을 반환하여 third-party cookie blocking이 우회됩니다. main frame URL이 owner-inherited document인 경우, FrameLoader::updateFirstPartyForCookies()는 opener의 firstPartyForCookies를 상속해야 합니다.

Source/WebCore/loader/FrameLoader.cpp

void FrameLoader::updateFirstPartyForCookies()
{
- if (RefPtr page = m_frame->page())
- setFirstPartyForCookies(page->mainFrameURL());
+ RefPtr page = m_frame->page();
+ if (!page)
+ return;
+
+ auto firstPartyForCookies = page->mainFrameURL();
+ if (SecurityPolicy::shouldInheritSecurityOriginFromOwner(firstPartyForCookies)) {
+ if (RefPtr opener = dynamicDowncast<LocalFrame>(page->mainFrame().opener())) {
+ if (RefPtr openerDocument = opener->document())
+ firstPartyForCookies = openerDocument->firstPartyForCookies();
+ }
+ }
+
+ setFirstPartyForCookies(firstPartyForCookies);
}

LayoutTests/http/tests/resourceLoadStatistics/third-party-cookie-blocking-about-blank-popup.html

+ case "#step2":
+ var popup = window.open("about:blank");
+ popup.eval(
+ "fetch('" + thirdPartyOrigin + "/cookies/resources/echo-cookies.py', { credentials: 'include' })" + ...
+ );

updateFirstPartyForCookies()는 기존에 frame의 firstPartyForCookiespage->mainFrameURL()로 무조건 설정했습니다. 수정 후에는 조건 검사가 추가되었습니다. main frame URL이 SecurityPolicy::shouldInheritSecurityOriginFromOwner()의 대상인 경우, page->mainFrame().opener()LocalFrame으로 downcast하여 opener document의 firstPartyForCookies()를 조회하고, 해당 값을 대신 사용하도록 변경되었습니다.

document URL이 about:blank와 같이 owner-inherited scheme인 경우, first-party-for-cookies 필드에 opener/parent 상속이 반영되지 않는 패턴.

firstPartyForCookies는 frame별로 관리되는 URL로, 외부로 나가는 요청에 기록됩니다. network layer는 이 URL의 registrable domain(eTLD+1)을 "first party"로 삼아 cookie 목적지가 first-party인지 third-party인지를 결정합니다. about:blank와 같은 opaque scheme의 경우, registrable domain은 빈 문자열이 됩니다. WebKit의 third-party cookie blocking(Intelligent Tracking Prevention)은 tracker로 분류된 목적지에 대한 cross-site subresource 요청의 cookie를 차단하는데, 이 결정은 thirdPartyCookieBlockingDecisionForRequest()를 통해 이루어집니다. HTML 명세에 따르면 about:blank document는 자신을 생성한 browsing context로부터 security origin을 상속받습니다. SecurityPolicy::shouldInheritSecurityOriginFromOwner(url)은 이 규칙을 따르는 URL scheme(about:blank, about:srcdoc, data: 등)에 대해 true를 반환합니다.

페이지에서 about:blank popup을 열면, popup의 main frame URL은 그대로 about:blank가 됩니다. 이때 updateFirstPartyForCookies()는 popup frame의 firstPartyForCookies를 해당 URL로 설정합니다. 이후 popup이 cross-origin 요청을 보내면, network layer가 about:blank의 registrable domain을 계산하여 빈 문자열을 얻게 됩니다. thirdPartyCookieBlockingDecisionForRequest()는 빈 registrable domain을 None으로 처리합니다. 비교 대상이 될 의미 있는 first party가 존재하지 않으므로, "차단하지 않음"으로 판단하는 것입니다.

🔒

Detailed analysis of the cookie-policy boundary that this opener-inheritance gap weakens, and the realistic conditions under which it can be triggered from web content

더 확인하려면 구독해 주세요

🔒

Multiple reusable audit patterns identified across WebKit's first-party / origin-inheritance machinery, with concrete grep starting points and a site-isolation caveat worth examining

더 확인하려면 구독해 주세요