Fire webRequest events for declarativeNetRequest-blocked loads
Component: WebKit Web Extensions | 162e023
Source/WebCore/contentextensions/ContentRuleListBlockedLoadInfo.h
declarativeNetRequest(dNR)의 block rule은 content rule list로 컴파일된 뒤, WebProcess 안에서 content-extension 엔진이 전부 처리합니다. 요청이 NetworkProcess까지 도달하기도 전에 차단이 끝나는 셈입니다. 그런데 webRequest 이벤트가 생성되는 지점은 바로 그 NetworkProcess입니다. 결과적으로 차단된 load는 webRequest 이벤트를 기다리는 extension 입장에서 전혀 관찰되지 않았습니다.
이번 commit은 차단이 실제로 수행되는 지점에 ChromeClient::contentRuleListDidBlockLoad hook을 추가했습니다. 이때 frame identifier, URL, method, resource type, 그리고 차단을 수행한 rule list의 identifier가 새로 도입된 ContentRuleListBlockedLoadInfo struct에 담겨 WebProcess에서 UIProcess로 전달됩니다. UIProcess는 blockingContentRuleListIdentifiers를 대조해 해당 rule list를 소유한 WebExtensionContext를 찾아냅니다. 이후 그 extension의 WebProcess proxy로 이벤트를 다시 내려보내 webRequest.onBeforeRequest를 먼저, 이어서 onErrorOccurred를 발생시킵니다. Chrome 및 Firefox와 동일한 동작입니다. 하드코딩되어 있던 net::ERR_ABORTED 문자열도 해당 load의 실제 localized error description으로 변경되었습니다.
Significance
dNR로 차단된 load에 대해 webRequest 이벤트가 전혀 생성되지 않던 관측 공백이 이번 변경으로 해소되었습니다. 자신이 등록한 block rule을 실제 트래픽과 대조하는 extension이라면, 스스로 유발한 차단 이벤트를 하나도 관찰하지 못하고 있었던 셈입니다.
Audit directions
앞으로 눈여겨볼 패턴은, 더 낮은 권한의 process가 제공한 identifier로 수신자가 결정되고 그 수신자에게 인위적으로 생성된 이벤트가 전달되는 구조입니다. 좁게 보면, WebExtensionController가 blockingContentRuleListIdentifiers를 기준으로 라우팅할 때 해당 rule list를 실제로 소유한 extension으로만 이벤트 범위가 엄격히 제한되는지 확인할 필요가 있습니다. 이 범위 제한이 없다면, 장악되었거나 상태가 어긋난 WebProcess가 자신의 것이 아닌 identifier를 보내는 경우를 가정할 수 있습니다. 이 경우 다른 extension의 context 안에서 observer callback이 실행되며, extension 사이의 confused deputy에 해당합니다. 조금 더 넓게 보면, 이 새로운 경계를 넘어가는 FrameIdentifier가 같은 질문의 나머지 절반입니다. WebChromeClient.cpp의 parentFrameIDForBlockedLoad를 대상으로, 차단 시점과 보고 시점 사이에 frame이 해제되는 경우를 점검해 볼 만합니다. stale하거나 어긋난 identifier가 UIProcess의 frame 조회로 들어가면, 이후 그 값을 사용하는 모든 지점에서 혼선의 출발점이 되기 때문입니다. 같은 두 가지 질문은 extension 계층의 다른 WebProcess→UIProcess→WebProcess 왕복 경로에도 그대로 적용됩니다. renderer 쪽에서 선택한 identifier가 메시지의 수신자를 결정하고, 정작 수신자는 그 메시지를 신뢰할 수 있는 것으로 취급하는 구조라면 동일한 점검이 필요합니다. 가장 넓게 보면, 권한을 가진 라우터가 신뢰할 수 없는 필드로부터 목적지를 고르는 모든 지점이 대상입니다. 이때 확인해야 할 것은 하나입니다. 해당 identifier의 소유권이, 보내는 process가 이미 보유하고 있다고 알려진 범위와 대조되어 검증되는지 여부입니다.