SecurityError : 출처가있는 프레임이 교차 출처 프레임에 액세스하지 못하도록 차단


555

<iframe>HTML 페이지에서를 로드하고 Javascript를 사용하여 HTML 내의 요소에 액세스하려고하지만 코드를 실행하려고하면 다음 오류가 발생합니다.

SecurityError: Blocked a frame with origin "http://www.<domain>.com" from accessing a cross-origin frame.

프레임의 요소에 액세스 할 수 있도록 솔루션을 찾도록 도와 줄 수 있습니까?

테스트 에이 코드를 사용하고 있지만 헛된 것입니다.

$(document).ready(function() {
    var iframeWindow = document.getElementById("my-iframe-id").contentWindow;

    iframeWindow.addEventListener("load", function() {
        var doc = iframe.contentDocument || iframe.contentWindow.document;
        var target = doc.getElementById("my-target-id");

        target.innerHTML = "Found it!";
    });
});

답변:


820

동일 출처 정책

JavaScript를 사용하여 다른 출처로 액세스 는 없습니다. 가능한 <iframe>경우 큰 보안 결함이 될 수 있습니다. 를 들어 동일 출처 정책 브라우저는 스크립트를 다른 원점 프레임에 액세스하려고 차단 .

주소의 다음 부분 중 하나 이상이 유지되지 않으면 출발지가 다른 것으로 간주됩니다.

<protocol>://<hostname>:<port>/...

프레임에 액세스하려면 프로토콜 , 호스트 이름포트 가 도메인과 같아야합니다.

참고 : Internet Explorer는이 규칙을 엄격하게 따르지 않는 것으로 알려져 있습니다 . 자세한 내용 은 여기 를 참조하십시오.

다음에서 다음 URL에 액세스하려고하면 어떻게됩니까? http://www.example.com/home/index.html

URL                                             RESULT 
http://www.example.com/home/other.html       -> Success 
http://www.example.com/dir/inner/another.php -> Success 
http://www.example.com:80                    -> Success (default port for HTTP) 
http://www.example.com:2251                  -> Failure: different port 
http://data.example.com/dir/other.html       -> Failure: different hostname 
https://www.example.com/home/index.html:80   -> Failure: different protocol
ftp://www.example.com:21                     -> Failure: different protocol & port 
https://google.com/search?q=james+bond       -> Failure: different protocol, port & hostname 

해결 방법

동일한 출처 정책으로 인해 스크립트가 다른 출처를 가진 사이트의 컨텐츠에 액세스하는 것을 차단하더라도 두 페이지를 모두 소유 한 경우 다음window.postMessagemessage 과 같이 두 페이지간에 메시지를 보내기 위해 관련 이벤트사용하여이 문제를 해결할 수 있습니다 .

  • 메인 페이지에서 :

    let frame = document.getElementById('your-frame-id');
    frame.contentWindow.postMessage(/*any variable or object here*/, 'http://your-second-site.com');

    두 번째 인수는 할 postMessage()수 있습니다 '*'대상의 기원에 대한 더 선호를 나타 내기 위해. 다른 사이트로 보내는 데이터를 공개하지 않으려면 가능한 한 항상 목표 출처를 제공해야합니다.

  • 귀하의 <iframe>(메인 페이지에 포함) :

    window.addEventListener('message', event => {
        // IMPORTANT: check the origin of the data! 
        if (event.origin.startsWith('http://your-first-site.com')) { 
            // The data was sent from your site.
            // Data sent with postMessage is stored in event.data:
            console.log(event.data); 
        } else {
            // The data was NOT sent from your site! 
            // Be careful! Do not use it. This else branch is
            // here just for clarity, you usually shouldn't need it.
            return; 
        } 
    }); 

이 메소드는 양방향으로 적용되어 메인 페이지에도 리스너를 생성하고 프레임에서 응답을 수신 할 수 있습니다 . 동일한 논리를 팝업과 기본적으로 메인 페이지에 의해 생성 된 (예 :를 사용하여 window.open()) 새 창에서도 구현할 수 있습니다 .

에 동일 출처 정책을 비활성화 하여 브라우저

이미이 주제에 대한 좋은 답변이 있습니다 (방금 찾은 인터넷 검색).이 가능한 브라우저의 경우 상대 답변을 연결합니다. 그러나 기억하십시오 동일 출처 정책을 해제하는 경우에만 영향을 미칠 것이다 당신의 브라우저를 . 또한 동일한 출처 보안 설정을 사용하지 않는 브라우저를 실행하면 모든 웹 사이트에 출처 간 리소스에 대한 액세스 권한이 부여 되므로 매우 안전하지 않으므로 수행중인 작업을 정확히 모르는 경우 (예 : 개발 목적) 수행해서는 안됩니다 .


27
1 , 2 에서 찾은 다른 답변 은 CORS / Access-Control-Allow-OriginiHRcanvas.drawImage 에만 적용되지 않으며 XHR, Fonts, WebGL 및 에만 적용 된다는 것을 나타 냅니다. 나는 postMessage유일한 옵션 이라고 생각 합니다.
snappieT

369
자바 스크립트에서 물결표 "~"연산자를 처음 보았습니다. 무엇을하는지 모르는 다른 사람들을 위해 : -1을 0으로 변환하여 indexOf의 결과에서 "! = -1"을 수행 할 필요가 없습니다. 개인적으로 "! = -1"을 사용하면 다른 프로그래머가 물결표를 넣는 것을 잊어 버린 버그를 쉽게 이해하고 피할 수있을 것입니다. 그러나 항상 새로운 것을 배우는 것이 좋습니다.
Redzarf

4
@SabaAhang은을 확인 iframe.src하고 사이트가 도메인의 호스트 이름과 다른 경우 해당 프레임에 액세스 할 수 없습니다.
Marco Bonelli

17
@Snuggs 완전히 잘못 ~, 수의 2의 보수를 반환 그렇게 n-n-1경우에만 의미 -1가 될 것이다 0(으로 해석되는 false) 및 기타 값은 테스트를 통과합니다. IE 0 = -(-1)-1는 아닙니다 -(-1+1).
Marco Bonelli

2
@ user2568374 location.ancestorOrigins[0]는 부모 프레임의 위치입니다. 당신의 프레임 내에서 실행중인 경우 다른 사이트 당신은 사용 체크 event.origin.indexOf(location.ancestorOrigins[0])이벤트의 기원은 부모의 프레임 주소가 포함 된 경우 확인하려는 항상 될 것입니다true 때문에 당신이 허용하고, 모든 부모모든 근원 이 당신의 프레임에 액세스하고, 분명히 당신이하고 싶은 일이 아닙니다. 또한 document.referrer위의 주석에서 이미 설명했듯이 나쁜 습관도 있습니다.
Marco Bonelli

55

마르코 보 넬리 (Marco Bonelli)의 답변 보완 : 프레임 / iframe 사이에서 상호 작용하는 가장 좋은 최신 방법은 모든 브라우저window.postMessage 에서 지원하는입니다.


21
이 링크가 질문에 대한 답변을 제공 할 수 있지만 여기에 답변의 필수 부분을 포함시키고 참조 용 링크를 제공하는 것이 좋습니다. 링크 된 페이지가 변경되면 링크 전용 답변이 유효하지 않을 수 있습니다. - 리뷰에서
Alessandro Cuttin

9
@AlessandroCuttin에 동의하지 않습니다. window.postMessage작동 방식을 설명 하면 이미 언급 한 허용 된 답변 만 복제됩니다. 또한 필자가 대답하는 필수 가치는 외부 문서를 참조하는 것의 정확한 가치입니다.
Geert

5
허용 된 답변을 수정하여 추가 할 수 있으면 더 좋습니다.
Martin Massera

12
window.postMessage 우리는 부모 (우리의 HTML 페이지)와 자식 요소 (다른 도메인 iframe)에 모두 액세스 할 수있는 경우에만 사용할 수 있습니다. 그렇지 않으면 "위치가 없습니다"라는 오류가 발생합니다. 교차 출처 프레임에 액세스 할 수없는 "< yourdomainname.com >"
VIJAY P

19

도메인 웹 서버의 http://www.<domain>.com구성을 확인하십시오. X-Frame-Options 클릭 재킹 공격을 방지하도록 설계된 보안 기능입니다.

clickJacking은 어떻게 작동합니까?

  1. 사악한 페이지는 희생자 페이지와 똑같습니다.
  2. 그런 다음 사용자가 자신의 사용자 이름과 비밀번호를 입력하도록 속였습니다.

기술적으로 악은 iframe희생자 페이지의 출처와 관련이 있습니다.

<html>
    <iframe src='victim_domain.com'/>
    <input id="username" type="text" style="display: none;/>
    <input id="password" type="text" style="display: none;/>
    <script>
        //some JS code that click jacking the user username and input from inside the iframe...
    <script/>
<html>

보안 기능 작동 방법

x-frame-options를iframe 추가하여 웹 서버 요청이 렌더링되는 것을 방지 하려면

X- 프레임 옵션 거부

옵션은 다음과 같습니다.

  1. SAMEORIGIN // 내 도메인에만 허용하여 HTML을 iframe 안에 렌더링합니다.
  2. 거부 // iframe 내에서 HTML을 렌더링 할 수 없음
  3. "ALLOW-FROM https://example.com/"// 특정 도메인이 iframe 내에서 HTML을 렌더링하도록 허용

이것은 IIS 구성 예입니다.

   <httpProtocol>
       <customHeaders>
           <add name="X-Frame-Options" value="SAMEORIGIN" />
       </customHeaders>
   </httpProtocol>

질문에 대한 해결책

웹 서버가 보안 기능을 활성화 한 경우 클라이언트 측 SecurityError가 발생할 수 있습니다.


1
X-Frame-Options가 여기에 적용되지 않는다고 생각합니다-게스트 (임베디드) 페이지에 의해 정의 된 X-Frame-Options는 부모가 페이지로드를 거부 할 수 있지만 자바 스크립트에 영향을 미치지 않는 한 액세스 - 심지어는 X-프레임 - 옵션 : *, 난 당신이 자바 스크립트로 다른 기원 게스트 페이지의 DOM에 액세스 할 수 있습니다 생각하지 않는다
노아 길모어

13

나를 위해 2-way 핸드 셰이크를 구현하고 싶었습니다
.- 부모 창이 iframe보다 빠르게로드됩니다
-iframe이 준비되는 즉시 부모 창과 대화해야합니다
-부모가 iframe 메시지를 수신하고 재생할 준비가되었습니다.

이 코드는 [CSS 사용자 정의 속성]
코드를 사용하여 iframe에서 화이트 라벨을 설정하는 데 사용됩니다 .
iframe

$(function() {
    window.onload = function() {
        // create listener
        function receiveMessage(e) {
            document.documentElement.style.setProperty('--header_bg', e.data.wl.header_bg);
            document.documentElement.style.setProperty('--header_text', e.data.wl.header_text);
            document.documentElement.style.setProperty('--button_bg', e.data.wl.button_bg);
            //alert(e.data.data.header_bg);
        }
        window.addEventListener('message', receiveMessage);
        // call parent
        parent.postMessage("GetWhiteLabel","*");
    }
});

부모의

$(function() {
    // create listener
    var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
    var eventer = window[eventMethod];
    var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
    eventer(messageEvent, function (e) {
        // replay to child (iframe) 
        document.getElementById('wrapper-iframe').contentWindow.postMessage(
            {
                event_id: 'white_label_message',
                wl: {
                    header_bg: $('#Header').css('background-color'),
                    header_text: $('#Header .HoverMenu a').css('color'),
                    button_bg: $('#Header .HoverMenu a').css('background-color')
                }
            },
            '*'
        );
    }, false);
});

당연히 당신은 원점과 텍스트를 제한 할 수 있습니다. 이것은 작업하기 쉬운 코드입니다.
이 examlpe가 도움이된다는 것을 알게되었습니다
.


iframe의 문서가 부모 페이지보다 나중에 JS를 실행하여 iframe의 문서보다 메시지가 더 일찍 전송되어 메시지를 수신하는 사파리 문제를 처리하고 있습니다. 크롬과 파이어 폭스와 정확히 반대되는 것입니다-iOS의 사파리에서 코드를 테스트 했습니까? btw postMessage 값이 "*"인 두 번째 매개 변수는 안전하지 않으므로 항상 domain을 지정해야합니다
sKopheK

첫 번째 코드 블록은 부모의 iframe에 있거나 iframe에로드 된 페이지에 있습니까?
Demonic218

0

이에 영향을 줄 수있는 Java Spring 특정 구성을 추가하고 싶습니다.

웹 사이트 또는 게이트웨이 애플리케이션에는 contentSecurityPolicy 설정이 있습니다.

Spring에서는 WebSecurityConfigurerAdapter 하위 클래스의 구현을 찾을 수 있습니다

contentSecurityPolicy("
script-src 'self' [URLDomain]/scripts ; 
style-src 'self' [URLDomain]/styles;
frame-src 'self' [URLDomain]/frameUrl...

...

.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)

안전한 외부 연결을 정의하지 않으면 브라우저가 차단됩니다.


0

iframe의 컨텐츠를 제어 할 수있는 경우 (즉, Amazon Mechanical Turk와 같은 교차 출처 설정에만로드 된 <body onload='my_func(my_arg)'>경우) 내부 HTML 의 속성 으로이 문제를 피할 수 있습니다 .

예를 들어, 내부 HTML의 경우 thishtml 매개 변수를 사용하십시오 (예- this정의되고 내부 본문 요소의 상위 창을 나타냄).

<body onload='changeForm(this)'>

내부 HTML에서 :

    function changeForm(window) {
        console.log('inner window loaded: do whatever you want with the inner html');
        window.document.getElementById('mturk_form').style.display = 'none';
    </script>

-24
  • 시작 메뉴를 엽니 다
  • windows + R을 입력하거나 "실행
  • 다음 명령을 실행하십시오.

chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security


3
빠르고 더러운 테스트에 좋습니다!
user1068352

6
빠르고 더러운 테스트가 아니고 이미 받아 들여진 답변으로 해결되지 않은 것은 끔찍합니다.
Quentin

2
Chrome에서이 방법으로 웹 보안을 사용 중지하지 않기 때문에 명령이 작동하더라도 작동하지 않습니다.
Metafaniel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.