본문 바로가기
Javascript

cross origin iframe - alert, confirm, prompt 사용 불가 이슈

by @hohoya33 2021년 07월 22일

iframe 내에서 alert, confirm, prompt 띄울 경우 오류가 발생

 

오류 내용:

A different origin subframe tried to create a JavaScript dialog. This is no longer allowed and was blocked. See https://www.chromestatus.com/feature/5148698084376576 for more details.

 

 

현재 크롬 같은 버전이라도 서브 버전에 따라 누구는 재현되고 안되고 할 수 있음

하지만 기능 제거는 확정된 사안인 만큼 가급적 선행 조치 필요함

 

 

 

Remove alert(), confirm(), and prompt for cross origin iframes - Chrome Platform Status

Motivation The current UI for JS dialogs (in general, not just for the cross-origin subframe case) is confusing, because the message looks like the browser’s own UI. This has led to spoofs (particularly with window.prompt) where sites pretend that a part

www.chromestatus.com

 

 

해결 방법


1. postMessage로 자식 페이지에서 띄울 메시지를 부모 페이지로 전달해서 alert으로 띄우기
2. 기본 네이티브 alert 대신 디자인 모달로 변경해서 띄우기

 

1번이 좋을 듯

2번은 아이프레임이라 모달 창 이슈 더 많을 것 같음

 

iframe인 경우 자식 페이지에서 띄울 메시지를 부모 페이지로 전달해서 alert으로 띄우는 방식 사용

 

참고 코드

 

자식 페이지 (iframe)
iframe으로 들어간 경우 postMessage로 부모 페이지에 메시지 전달 후 부모 페이지에서 alert으로 띄움

 

alert("이거 뿌려 주세요."); -> customAlert("이거 뿌려 주세요.");

function customAlert(message) { 
  if (window.self !== window.top) {
    console.log('iframe loaded');

    window.parent.postMessage({
      action: "systemAlert",
      message: message
    }, "*");
  } else {
    alert(message);
  }
}

 

부모 페이지

전달받은 메시지를 부모 페이지에서 다시 alert으로 띄우기

function systemAlert(message) {
  alert(message);
}

window.addEventListener("message", (event) => {
  // 메시지의 오리진을 체크하여 신뢰할 수 있는 메시지인지를 확인
  // if (event.origin !== "http://localhost:3000") {
  //  return;
  // }

  var data = event.data;

  if (typeof(window[data.action]) == "function") {
    window[data.action].call(null, data.message);
  }
}, false);

 

Override alert

자바스크립트 alert 함수 오버라이드(override)하여 사용하기

window.alert = (function (original) {
  return function (msg) {
    if (window.self !== window.top) {
      window.parent.postMessage({
        action: "systemAlert",
        message: msg
      }, "*");
    } else {
      original(msg);
    }
  }
})(window.alert);

 

confirm(), prompt()

confirm, prompt의 경우 부모 페이지에서  confirm, prompt 창을 띄우고 입력된 값을 다시 iframe으로 보내야 하기 때문에 약간 까다롭습니다.

 

구글은 다음에 또 무엇을 할까요..? 이제 window.postMessage()를 비활성화시킬까요? 

개발자들은 이것 저것 테스트해보느라 여기에 많은 시간을 투입하게 되네요. 다시 Internet Explorer 시대로 돌아가는 게 아닌지..

 

parent.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Parent (domain A)</title>
        <script type="text/javascript" src="https://example.com/dialogs.js"></script>
    </head>
    <body>
        <h1>Parent (domain A)</h1>
        <iframe src="https://example-b.com/iframe.html">
    </body>
</html>

 


iframe.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Iframe (domain B)</title>
        <script type="text/javascript" src="https://example.com/dialogs.js"></script>
    </head>
    <body>
        <h1>Iframe (domain B)</h1>
        <script type="text/javascript">
            alert('alert() forwarded from iframe.html');
            
            confirm('confirm() forwarded from iframe.html via callback', (result) => {
                console.log('confirm() result via callback: ', result);
            });

            prompt('prompt() forwarded from iframe.html via callback', null, (result) => {
                console.log('prompt() result via callback: ', result);
            });
            
            (async () => {
                var result1 = await confirm('confirm() forwarded from iframe.html via promise');
                console.log('confirm() result via promise: ', result1);

                var result2 = await prompt('prompt() forwarded from iframe.html via promise');
                console.log('prompt() result via promise: ', result2);
            })();
        </script>
    </body>
</html>

 

 

dialogs.js

(function() {

    var id = 1,
        store = {},
        isIframe = (window === window.parent || window.opener) ? false : true;

    // Send message
    var sendMessage = function(windowToSend, data) {
        windowToSend.postMessage(JSON.stringify(data), '*');
    };

    // Helper for overridden confirm() and prompt()
    var processInteractiveDialog = function(data, callback) {
        sendMessage(parent, data);

        if (callback)
            store[data.id] = callback;
        else
            return new Promise(resolve => { store[data.id] = resolve; })
    };

    // Override native dialog functions
    if (isIframe) {
        // alert()
        window.alert = function(message) {
            var data = { event : 'dialog', type : 'alert', message : message };
            sendMessage(parent, data);
        };

        // confirm()
        window.confirm = function(message, callback) {
            var data = { event : 'dialog', type : 'confirm', id : id++, message : message };
            return processInteractiveDialog(data, callback);
        };

        // prompt()
        window.prompt = function(message, value, callback) {
            var data = { event : 'dialog', type : 'prompt', id : id++, message : message, value : value || '' };
            return processInteractiveDialog(data, callback);
        };
    }

    // Listen to messages
    window.addEventListener('message', function(event) {
        try {
            var data = JSON.parse(event.data);
        }
        catch (error) {
            return;
        }

        if (!data || typeof data != 'object')
            return;

        if (data.event != 'dialog' || !data.type)
            return;

        // Initial message from iframe to parent
        if (!isIframe) {
            // alert()
            if (data.type == 'alert')
                alert(data.message)

            // confirm()
            else if (data.type == 'confirm') {
                var data = { event : 'dialog', type : 'confirm', id : data.id, result : confirm(data.message) };
                sendMessage(event.source, data);
            }

            // prompt()
            else if (data.type == 'prompt') {
                var data = { event : 'dialog', type : 'prompt', id : data.id, result : prompt(data.message, data.value) };
                sendMessage(event.source, data);
            }
        }

        // Response message from parent to iframe
        else {
            // confirm()
            if (data.type == 'confirm') {
                store[data.id](data.result);
                delete store[data.id];
            }

            // prompt()
            else if (data.type == 'prompt') {
                store[data.id](data.result);
                delete store[data.id];
            }
        }
    }, false);

})();

 

 

 

 

Apps Script Alert(), Confirm(), Promote does not work any longer

Apps script web app works in . It seems Chrome are no longer support Alert(), Confirm(), Promote these functions on the web app. Any work around to this? Chrome Version 92.0.4515.107 (Official Buil...

stackoverflow.com

 

 

관련 논의

 

Intent to Remove: Cross origin subframe JS Dialogs

Joe Medley 읽지 않음, 2021. 5. 6. 오후 11:45:415월 6일  작성자에게 답장하려면 로그인하세요. 전달하려면 로그인하세요. 이 그룹의 메시지를 삭제할 권한이 없습니다. 메시지를 악용사례로 신고하

groups.google.com

 

개의 댓글