postMessageを使ってクロスオリジンでメッセージをやりとりする

August 20, 2016

クロスオリジンなwindow間でメッセージをやりとりしたくなり、postMessageについて調べました。

postMessage

https://developer.mozilla.org/ja/docs/Web/API/Window/postMessage

クロスオリジンなwindow間でメッセージをやりとりするためのAPI。 名前の通りメッセージの送り手と受け手という概念が存在します。

送り手はデータを送る際にオリジンを指定します。 指定されたオリジンが送信先windowのオリジンと異なる場合は送信できません。 ただし、'*‘を指定した場合はオリジンの一致に関わらずメッセージが送信されます。

受け手はwindowのmessageイベントを待ちます。 メッセージが送信されるとmessageイベントが起き、指定されたハンドラーが実行されます。

iframeのサイズを中のコンテンツサイズに合わせて動的に調整する例は以下のようになります。

parent.html

<iframe id='iframe' src='https://ssl.my.domain.com/' style='width: 200px; height: 100px'></iframe>
<script>
  var frame = document.getElementById('iframe');
  frame.onload = function() {
    frame.contentWindow.postMessage('getSize', frame.src);
  };
  window.addEventListener('message', function(e) {
    console.log('From: ' + e.origin);
    // 指定のオリジン以外の場合は処理をスキップする
    if(e.origin === 'https://ssl.my.domain.com') {
      frame.setAttribute('style', 'width: ' + e.data.width + 'px; height: ' + e.data.height + 'px;');
    }
  });
</script>

child.html

<div id='content'>
  Hello World!
</div>
<script>
  window.addEventListener('message', function(e) {
    console.log('From: ' + e.origin);
    var content = document.getElementById('content');
    e.source.postMessage({
      height: content.clientHeight,
      width: content.clientWidth
    }, e.origin);
  });
</script>

オリジンの指定が一致しない場合

対象windowのオリジンと異なるオリジンを指定すると、エラーが発生して送信されません。

frame.contentWindow.postMessage('getSize', 'http://other.domain.com');
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://ssl.my.domain.com') does not match the recipient window's origin ('http://other.domain.com')

オリジンの指定を’*‘にした場合

送信先オリジンを’*‘にすると対象オリジンに関わらず送信されます。

frame.contentWindow.postMessage('getSize', '*');

オリジンチェック

メッセージの送信自体はwindowオブジェクトにアクセスさえできれば送信可能です。 したがって、悪意を持ったスクリプトから怪しいメッセージが送られてくる可能性もあります。 messageイベントを処理する際は、送信元のオリジンやメッセージのフォーマットが意図したものであるかを必ずチェックしましょう。

コード

こちらです。

https://github.com/hokuma/post-message-sample

comments powered by Disqus