129Implement a secure postMessage communication protocol between a parent page and embedded iframe
Problem
Your page embeds a payment widget in a cross-origin iframe. They need to talk: the parent asks for the widget's height, the widget reports "payment completed". Any other page or frame can also send messages to either window, so every message must be treated as hostile until proven otherwise.
Implement createSecureChannel({ self, target, targetOrigin, allowedOrigin, protocol = "fp-rpc/1", timeout = 3000, createId = () => crypto.randomUUID() }):
self: where messages arrive (windowin a browser; anything withaddEventListener("message", …)).target: the other window (iframe.contentWindoworwindow.parent); it haspostMessage(data, targetOrigin).- Returns
{ connect(), handle(type, handler), request(type, payload), close() }.
Protocol:
- Handshake:
connect()sends{ protocol, kind: "hello", session }with a fresh random session id and resolves when the other side answers{ kind: "ready", session }. The receiving side adopts the session from a validhelloand repliesready. Until then, it ignores requests. - RPC:
request(type, payload)sends{ protocol, kind: "request", session, id, type, payload }and resolves with the result, or rejects with the handler's error message, or with an error named"TimeoutError"aftertimeoutms.requestbefore a session exists rejects. handle(type, handler)registers an async handler; the response is{ kind: "response", session, id, ok, result | error }. Unknown types answer with an error.
Security rules for every incoming message: ignore it unless event.origin === allowedOrigin, event.source === target, the data is an object with the right protocol, a known kind, the expected fields, and (after the handshake) the current session. Always send with the exact targetOrigin, never "*". Never throw on bad input.
Try it yourself
Write your solution, run it, then submit to check it against the tests.
Press Run or ⌘ Enter to execute your code.
Step-by-step
event.origin is set by the browser and cannot be forged, so compare it exactly with the expected origin (never with startsWith or includes: https://pay.example.com.evil.net starts with your origin). event.source tells you which window sent it; checking it rejects other frames from the same origin, such as a second widget instance.
Unlock the full solution
What's inside
- Step-by-step
- Approach
- Solution
- Complexity
- Edge cases
- Follow-up questions
- Tests
Includes 2 code listings, 5 edge cases, 4 follow-up questions.
One-time payment by UPI, card or net banking. Launch price.