[javascript] iframe

dev stefanCho·2021년 8월 31일
0

iframe


iframe은 parent html과는 독립적인 execution context를 갖고 있다. (즉, script가 따로 돌아간다.)



iframe html 선택하기


console에서 html을 선택할 수 있다.



access iframe window


iframe에서 parent와 child간의 access가 가능하기 위해서는 아래 조건이 만족 되어야 한다.

  1. iframe에 sandbox attribute가 없어야함
  2. iframe에 sandbox attribute가 있다면, sandbox="allow-same-origin" 이어야함
  3. parent html과 iframe간에 Domain, Port, Protocol(http vs https)가 일치해야 함
  • parent -> child 로 access 하려면 document.querySelector('iframe').contentWindow 로 접근 (contentWindow 참고)

  • child -> parent로 access하려면 parent로 접근 하면 됨



iframe을 이용한 app


아래 이미지는 codepen.io가 어떻게 front app과 통신하는지 보여주는 이미지이다.

iframe이 reload되면, iframe 자체의 html과 js로 cdpn.io와 통신한다. (iframe에서 직접적인 access가 불가능하게 하려면, 다른 domain을 써야 하므로 codepen.io가 아닌 다른 이름의 도메인(cdpn.io)를 사용한다.)

image reference: Udemy course (Typescript: The Complete Developer's Guide by Stephen Grider)



sandbox property

Applies extra restrictions to the content in the frame. The value of the attribute can either be empty to apply all restrictions, or space-separated tokens to lift particular restrictions - MDN


sandbox property를 사용하면, iframe html에서 parent html에 접근하는것을 막을 수 있다.

source codeiframe DOM access blocking
  • pros : 위 이미지에서처럼 cdpn.io와 같은 독립적인 서버가 필요없다. (Domain, Port, Protocol이 다르면, DOM 접근을 막을 수 있음)
  • cons : iframe에 있는 html은 localStorage의 사용이 불가능하다.
// index.html
// srcDoc은 src와 달리 request없이 사용할 수 있다.
<iframe sandbox="" srcDoc={html} />

(...생략)

const html = `<h1> Hello World! </h1>`;

위에서는 sandbox=""로 해줬기 때문에, script를 실행 시킬 수 없다. (빈 공백은 html을 load하는 것만 허락한다.)

아래처럼 sandbox="allow-scripts"로 iframe을 load하면서 script가 실행되도록 할 수 있다. 즉 sandbox는 iframe의 실행과 관련된 property이다.

아래 코드를 참고해보자.
  const html = `
    <script>
    ${code}
    </script>
  `;

  return (
    <div>
      <textarea value={input} onChange={(e) => setInput(e.target.value)} />
      <div>
        <button onClick={onClick}>Submit</button>
      </div>
      <pre>{code}</pre>
      <iframe sandbox="allow-scripts" srcDoc={html} />
    </div>
  );



iframe을 사용을 고려하는 이유


아래 이유들은 iframe에서 parent html의 DOM에 접근을 막아야하는 이유가 될 수 있다.

  1. error 발생으로 인한 code crash를 방지할 수 있다. (iframe내에서만 에러가 발생한다.)
  2. 사용자가 DOM을 임의로 조작하는 것을 막을 수 있다. (DOM을 마음대로 바꿔버리면 app이 crash될 수 있다.)
  3. malicious user에 의해 임의로 코드가 조작되는 것을 막을 수 있다. (사용자가 코드를 입력할 때, 그 코드 입력을 다른 사용자가 조작할 수도 있기 때문이다.)



iframe안에 npm script를 직접 넣으면 안되는 이유


import ReactDOM from 'react-dom'을 해보았다. 아래 에러가 발생하였다.

확인을 해보니, 코드가 중간에 끊겨있다? (마지막에 뜬근없이 <script>가 있다.)
이유를 보아하니, import한 react-dom의 코드중간에 <script></script>인 부분이 있다.

위 예제에서

  const html = `
    <script>
    (...)<script></script> // <--- /script 에 의해서 예상치 못한 시점에 script태그가 끊어진것, 그리고 앞에 있는 <script>가 string으로 들어간것이다.
    </script>
  `;

아래 이미지가 문제의 구간이다. unpkg의 react-dom 코드에서 찾아볼 수 있다.



iframe의 간접적인 code 전달 방법


parent와 iframe간에는 통신하는 방법이 있다.
postMessage를 이용하는 것이다.

contentWindow.postMessage(message, targetOrigin)으로 보내고, iframe의 script에 window.addEventListener('message', callback)을 추가하여, message를 받을 수 있다.
postMessage의 두번째 parameter는 targetOrigin으로, '*'을 넣으면 모든 origin(parent-url)로 부터 접근을 허용하는 것임.

이 방법을 이용하면, iframe의 <script></script>안에 직접 string으로 된 code를 넣을 필요가 없다. (iframe에서 js를 실행하기 위해서 script tag 안에 code를 직접 넣는것은 program의 crash를 만들 수 있다.)

profile
Front-end Developer

0개의 댓글