[7] label-forwarded clicks promoted to isTrusted=true via dispatchSimulatedClick
Severity: Medium | Component: WebCore DOM event dispatch | fc1ef83
<label> forwarding을 통해 Event.isTrusted를 매번 재현 가능한 방식으로 스푸핑할 수 있는 경로를 수정하여 Medium으로 평가합니다. 직접적인 영향은 <input type=checkbox switch>의 haptic feedback trusted-event gate 우회이며, 더 넓은 영향 범위는 label 연결 컨트롤의 click에 대해 isTrusted를 조건으로 삼는 다른 기능들에 따라 달라집니다.
288403@main에서는 <input type=checkbox switch>의 haptic feedback에 user activation이 필요하도록 했습니다. 이와 함께 haptic이 trusted event에서만 발생해야 한다는 요구사항도 있었습니다. 그러나 input과 연결된 label에 click()을 호출하면 이 조건을 우회할 수 있었습니다. 근본적인 원인은 Element::dispatchSimulatedClick이 무조건 SimulatedClickSource::UserAgent를 설정하는 데 있습니다. 수정 내용은 underlying event가 존재하고 untrusted인 경우 SimulatedClickSource::Bindings를 지정하는 것입니다.
Source/WebCore/dom/Element.cpp
bool Element::dispatchSimulatedClick(Event* underlyingEvent, SimulatedClickMouseEventOptions eventOptions, SimulatedClickVisualOptions visualOptions)
{
- return simulateClick(*this, underlyingEvent, eventOptions, visualOptions, SimulatedClickSource::UserAgent);
+ auto simulatedClickSource = [&] {
+ if (!underlyingEvent)
+ return SimulatedClickSource::UserAgent;
+
+ return underlyingEvent->isTrusted() ? SimulatedClickSource::UserAgent : SimulatedClickSource::Bindings;
+ }();
+
+ return simulateClick(*this, underlyingEvent, eventOptions, visualOptions, simulatedClickSource);
}
LayoutTests/fast/forms/label/label-click-event-dispatch-untrusted.html
+<input id="input" type="checkbox">
+<label id="label" for="input"></label>
+<script>
+input.addEventListener("click", (event) => {
+ shouldBeFalse("event.isTrusted");
+});
+label.click();
+</script>
Patch Details
Element::dispatchSimulatedClick는 이제 underlying event의 신뢰 상태를 바탕으로 SimulatedClickSource를 결정합니다. underlying event 자체가 trusted인 경우에만 UserAgent를 사용하고, 그렇지 않으면 Bindings를 사용합니다. underlying event가 없는 경우(Element::click() 자체가 사용하는 경로)에는 동작이 변경되지 않습니다. layout test는 label.click()이 연결된 input에 untrusted click을 생성하는 것을 검증하며, WPT expectation이 FAIL에서 PASS로 전환됩니다. 또한 SwitchInputTests.mm은 실제 사용자 click에서는 haptic feedback이 발생하지만, user gesture 이후의 label-forwarded programmatic click에서는 발생하지 않음을 단언합니다.
내부 event-forwarding 경계를 넘을 때 underlying event의 trust bit가 전파되지 않아, untrusted event가 forwarded target에서 trusted로 재레이블링되는 패턴.
Background
Event.isTrusted는 user agent가 사용자 입력에 반응하여 event를 생성한 경우에만 true가 되는 boolean 플래그입니다. autoplay, fullscreen, clipboard, haptics 등 보안 및 프라이버시에 민감한 많은 API는 user activation 외에도, 또는 user activation 대신 이 플래그를 조건으로 삼습니다. SimulatedClickSource는 WebKit 내부 enum으로, UserAgent는 합성된 click을 isTrusted = true로 dispatch하고, Bindings는 isTrusted = false로 dispatch합니다. Element::dispatchSimulatedClick(Event* underlyingEvent, ...)는 다른 event를 대신하여 합성 click을 전달하는 helper입니다. tree 내에서의 주된 호출 지점은 <label> 요소로, label에 대한 click을 연결된 form 컨트롤로 전달합니다. Element::click()(IDL로 노출된 메서드)은 underlying event 없이 simulateClick을 직접 호출하는 별도의 경로이며, 설계 상 항상 untrusted입니다. user activation과 event trust는 독립적인 신호입니다. activation은 document 수준에서 최근 상호작용을 추적하고, isTrusted는 개별 event 객체의 출처를 추적합니다. trusted-event 검사는 user activation 검사보다 엄격한 조건입니다. activation은 실제 gesture 이후에도 잠시 유지될 수 있기 때문입니다.
Analysis
Element::dispatchSimulatedClick는 label에서 전달되는 모든 simulated click에 SimulatedClickSource::UserAgent를 하드코딩했습니다. trust laundering 흐름은 다음과 같습니다. JS에서 발생한 untrusted label.click()이 시작점입니다. HTMLLabelElement는 이를 dispatchSimulatedClick(underlyingEvent=<untrusted click>) 형태로 연결된 컨트롤에 전달합니다. 이때 <input type=checkbox switch>에 대한 simulated click이 SimulatedClickSource::UserAgent로 dispatch됩니다. 결과적으로 user activation 외에 trusted event를 요구하는 288403@main의 haptic-feedback gate가 해당 event를 trusted로 수락하게 됩니다.
Aaa Aaaaaaa Aaaa Aa Aaa Aaa Aaaaa Aa Aaaaaaa Aaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaaa Aa Aaaaa Aaaaaa Aaaaaa Aa Aa Aa Aaa Aaaaaaaa Aa Aaa Aaaaaaaa Aaaaaaaa Aaaaaa a Aaaaaaaa Aa Aaaaaaa Aa Aaaaa Aaaaa Aaaaa Aaaa Aaaaaaaaaa Aaa Aaaaa Aaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaaaaa Aaaaaaaaaa Aaaaaa Aaaaaaaaa Aaaaa Aaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaa a Aaaaaaaaa Aaaaaa Aaaaaaaaaaaaaaaaaa Aaaaa Aaa Aaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aa Aaaa Aaaaaaaaa Aaaaaa Aaaaaaaaaa a Aaaaaa Aaaaaaaaaaa Aaaaaaaaaaa Aaa Aaaa Aaaaaaaaaaaaaaa Aaaaaaaaaaaaa Aaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aa a Aaa Aaa Aaa Aaaaaa
a Aaaaaaaaaaaaaa Aaaa Aaaa Aaaaaa Aaaaa Aaaa Aaaaaa Aaaa Aaaaaaaaaaaaaaaaa Aa Aaa Aaaaaaaa Aaaa Aaa a Aa Aaaaaaaaaa Aaaaaa Aaa Aaaa Aaaa Aaaa Aa Aaaaa Aaaaaa Aaaaaaaaaaaaaaaaa Aaaa Aaaaa Aaa Aa Aaa Aaa Aa a Aaaaa Aa Aaaa Aaaaa Aaaaaa Aa Aaaaaaaaaaaa Aaaa Aa Aa Aaaa Aaaaa Aa Aaaaaa Aa Aaaaaaaaaaaaaaaa Aaaaaa Aaaa Aaaaaaaaaaaa Aaa Aaaaa Aaa Aaaaa Aaa Aa Aa Aaaaaa a Aaaaaaa Aaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaa Aa Aaaaa Aaaaa Aaaa Aaaaaa Aaaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aa Aaa Aaaa Aaaaaa Aaa Aaa Aaaaaaaaaa Aaaaaa Aaaaa Aaaaa Aaaaaaaaa Aaaaaaa Aaaaa Aaaaaaaaaa Aaaaaa Aa Aa Aaaaaaaaaaaa Aaaaaaaaaa Aaaaaa Aaaaaaa a Aaaaaaa Aa Aaa Aaaaaa Aaaa Aa Aa Aaaa Aaaa Aaa Aaa Aaaaa
🔒Walks through how a script-initiated event can cross an internal forwarding boundary inside WebCore and emerge with elevated trust — and what realistic policy gates that lets a page bypass from ordinary web content.
더 확인하려면 구독해 주세요
Audit directions
a Aaaa Aaaaaaaaaaaaaaaa Aaaaaa Aaa Aaaaaaaaaaa Aaaaaaaaaaaaa a Aaaaaaa Aa Aaa Aaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaaaaaaaa Aaaaa Aaaa Aaaaaaa Aa Aaa Aa Aaaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaaa Aaaaaaaaaaaaaaaaaa Aaa a Aaaa Aaaaaaaaaaaa Aaa Aaaa Aaa Aaa Aaa Aaaaaa
a Aaaaaaaaaaa Aaaaaaaaaaaa Aa Aaa Aaaa Aaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaa Aa Aaaaaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaaa Aaaaaaaa Aa Aaaaaaaaaaaaa Aaa Aaaaa Aaaaaaaaaaaaaaa Aaaaa a Aa Aaaa Aaaaaaaaaa Aaa Aa Aaa Aaaa Aaaaaa Aaaa Aaaa Aaa Aaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaa Aaaaaaa
a Aaaaaa Aaaa Aaa Aaaa Aa Aaaaaaa Aaaaaaaaaaaaaa Aaaaaa Aaa Aaaaaaa Aaaaaa Aaaaaaaa Aaaaaaa Aaaaaaaaaa Aaaaa Aaaaaaa Aa Aaaa Aaaaa Aaaaaaaaaaaa Aaaaa Aaaaa Aaaa Aaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaa Aaaaaa a Aaaaaaaa Aaa a Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaa Aaaaaa Aaa Aa Aaaaaa
a Aaaaaaaaaaaaaaa Aaaaa Aaaaa Aa Aaa Aaaaaaaaaaaaaaa Aaaaaaa Aaaaa Aaaaaaaaaa Aaaa Aaaa Aaaa Aaaa Aaaaaaaaaaaa Aa Aaaaa Aaaaaa Aaaaaa Aaaaaaaaaaa Aaa Aaa Aaaa Aaaa Aaa Aaaa Aa Aaaa Aaaaaa Aa Aaaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaaa Aaaaaaaaa Aa Aa Aa Aaaa Aa Aaaa Aaaa Aaa Aaaaa
🔒Several reusable audit patterns for event-trust laundering across WebKit's synthesized-event helpers, with concrete grep targets and subsystems to start with.
더 확인하려면 구독해 주세요