Iframe 태그와 origin이 다른 iframe 내부 dom tree 조작에 대해서
회사에서 다른 origin을 가진 iframe 내부 dom tree에 접근해야할 일이 생겼는데, 이 때 시도해 본 여러가지 방법에 대해서 적겠습니다.
결론은 "안된다"는 겁니다. 왜 안 되는지에 대해 적어보고자 합니다.
iframe과 내부에 있는 html을 단순히 확인하는 것은 가능합니다.
그러나 iframe 내부에 있는 google doc을 조작하는 것은 보안상의 문제로 불가능합니다.
그럼에도 불구하고 시도해본 것들은 다음과 같습니다.
시도 1) contentWindow을 사용하여 접근하려는 경우
contentWindow란 부모 window에서 임베디드된 <iframe>을 참조할 때 사용되는 메서드입니다.
https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/contentWindow
그러나 저희 typed에서 iframe 내부 에디터를 contentWindow로 확인해보려고 하면 다음과 같은 에러 메세지를 출력합니다.
Uncaught DOMException: Blocked a frame with origin "<http://localhost:5000>(client)" from accessing a cross-origin frame.
위 에러 메세지의 의미는 저희 측의 origin이 iframe의 origin과 같지 않으므로 접근할 수 없다는 것입니다.
이는 브라우저의 동일 출처 정책(same origin policy)과도 관련이 있습니다. 아래 문서를 참고해주세요.
https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
// origin을 출력해보고 싶다면...
window.location.origin
시도 2) contentDocument을 사용하여 접근하려는 경우
https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/contentDocument
If the iframe and the iframe's parent document are Same Origin, returns a Document
결론적으로는 origin이 같지 않으므로 contentDocument는 null을 반환하고, 실제로 null을 반환하는 것도 확인했습니다.
시도 3) 부모 Browsing Context 에서 자식 Browsing Context에 위치한 DOM에 직접 접근하려는 경우
단순히 내부 DOM을 출력하지 않습니다.
// iframeDom은 document.getElementById('iframe') 꼴로 가져온 형태임.
// <iframe>...</iframe> 꼴
iframeDom.querySelectorAll('*')// NodeList가 비어있음
시도 4) postMessage를 통해 데이터 전달???
특정 data를 iframe 내부에 전달해서 google editor 내부에 삽입할 수 있지 않을까하는 막연한 생각에 조사해보았습니다.
Window.postMessage 메서드를 통해 부모, 자식 browser context간 소통을 할 수 있습니다.
https://developer.mozilla.org/ko/docs/Web/API/Window/postMessage
targetWindow.postMessage(message, targetOrigin, [transfer]);
그러나 저희 typed에서 사용하려고 할 때
(1) 다른 origin의 정보를 담고 있는 iframe의 contentWindow에 접근하는 것 자체가 불가능하므로 해당 메서드를 사용할 수 없습니다.
(2) 애초에 남의 origin에 script를 삽입한다는 것 자체가 웹 해킹입니다.
// parent browser context
window.addEventListener('message', function (event) {
console.log(event.data) // { data: 'parent' }
// 애초에 same origin policy로 인하여 contentWindow에 접근 불가
document.getElementById('iframe').contentWindow.postMessage({data: "haha"}, '*') })
// iframe child browser context.
// 그러나 애초에 script를 삽입할 수 없음.
<script>
window.onload = function() {
window.parent.postMessage({ data: 'parent' }, '*');
};
window.addEventListener('message', function(e) {
console.log(e.data); // {data: "haha"} } );
</script>
시도 5) iframe Dom을 click() 이벤트를 발생시켜 editor에 포커스 시킨 다음 text를 삽입하려는 경우
const clipData = await navigator.clipboard.readText()
// click 이벤트를 발생시켜도 별다른 반응이 없음
iframeDom.click()
// 그리고 google doc을 아래와 같이 가져올 수도 없음
document.querySelector('.editor').innerText += clipData