App badge IPC sender-origin validation
Component: WebKit UIProcess | fd1fbad
Tools/TestWebKitAPI/Tests/WebKit/WKWebView/Badging.mm
Tools/TestWebKitAPI/Helpers/cocoa/HTTPServer.h
WebKit의 multi-process architecture는 UI process를 trust boundary로 취급합니다. WebContent process는 sandbox 안에서 동작하며 언제든 compromise될 수 있다고 가정되므로, 이 process가 보내는 IPC message 중 UI-process가 관리하는 state에 영향을 주는 것은 반드시 별도로 검증되어야 합니다. 즉 해당 WebContent process가 실제로 대변할 권한이 있는 대상인지를 독립적으로 확인해야 합니다. Badging API는 service worker와 페이지가 앱 아이콘에 숫자 badge를 설정할 수 있게 해주는 기능으로, 이 업데이트는 WebContent에서 UI process로 IPC를 통해 전달됩니다. 이번 commit은 이 메시지에 sender-origin validation을 추가하여, 특정 worker origin에 대한 badge를 실제로 갱신할 권한이 있는 WebContent process인지 UI process가 먼저 확인하도록 했습니다. 테스트 코드의 변경도 같은 맥락을 담고 있습니다. Badge delegate는 이제 단순히 어떤 badge 값이 도착했는지가 아니라 fromOrigin이 예상되는 요청 origin과 일치하는지를 검사하며, HTTPServer에는 cross-origin spoofing 시나리오를 재현할 수 있도록 multi-origin 설정 기능이 추가되었습니다.
Before: After:
WebContent (compromised) WebContent (compromised)
└─ IPC: setAppBadge(origin=X) ──► └─ IPC: setAppBadge(origin=X) ──►
UI process UI process
└─ applies badge for origin X └─ validate: does this WebContent
(no origin ownership check) process actually own origin X?
├─ yes ──► apply badge
└─ no ──► reject/ignore
Significance
패치 이전에는 compromise된 WebContent process가 임의의 origin을 사칭하는 badge-update IPC를 보낼 수 있었고, 그 결과 실제로는 다른 사이트에서 온 것처럼 앱 badge를 spoofing할 수 있었습니다. 이는 sandbox escape에 준하는 권한 문제에 해당합니다. UI process가 sandbox 안의 renderer로부터 검증되지 않은 origin 주장을 그대로 신뢰했기 때문이며, 더구나 이 메시지의 효과는 renderer가 통제할 수 없는 영역인 사용자에게 보이는 브라우저 UI 셸에 직접 반영됩니다.
Audit directions
이번 건은 권한을 가진 UI-process handler에서 확인된, 이미 수정이 완료된 IPC origin-validation 공백입니다. 유사한 버그를 찾는 데 좋은 template이 됩니다. 좁게 보면, WebContent에서 UI process로 가는 IPC message 중 스스로 보고하는 origin이나 identity parameter를 담고 있는 것들을 모두 나열하고, 각각이 동등한 sender-origin ownership check를 수행하는지 점검할 필요가 있습니다. Notification, permission prompt, favicon 및 title 업데이트, 그리고 Badging과 인접한 다른 API들이 우선 살펴볼 대상입니다. 넓게 보면, 동일한 패턴은 UI-process handler가 SecurityOriginData나 ClientOrigin 인자를 메시지에서 그대로 받아 사용하고, sending connection의 알려진 page/frame binding으로부터 다시 도출하지 않는 곳이라면 어디서든 재발할 수 있습니다. 코드 리뷰에서 눈여겨볼 신호는 origin parameter를 받는 handler 시그니처에서 첫 statement로 allowsFirstPartyAccess() 유형의 검사가 빠져 있는 경우입니다. 가장 넓게 보면, 핵심 invariant는 권한을 가진 receiver가 payload에서 principal을 읽어오는 대신 자신이 통제하는 channel로부터 principal을 다시 도출해야 한다는 것이며, 이는 RenderFrameHost에 bind된 모든 Mojo receiver와, caller가 스스로 자신의 identity를 명시하는 모든 RPC 표면에 그대로 적용됩니다.