Frontend crossdomain issue in IE

최근에 서비스를 오픈하면서 겪은 경험담 하나 정리해볼려고 한다.

백엔드 개발자로써 격는 크로스도메인 이슈를 통칭해서 CORS와 관련된 문제라고 이야기한다. API에 대한 요청이 동일 도메인이 아닌 경우에 발생할 수 있는 이슈다. 대부분 정책적인 문제와 관련된 것이라 도메인에 대한 접근 제어 혹은 권한 제어를 통해 해결의 실마리를 찾는다.

이 비슷한 문제가 Frontend쪽에서도 발생할 수 있다는 걸 작업 과정에서 알게 됐다. 문제의 개요를 간단히 설명해보면…

  1. AA 도메인 및 BA 도메인은 A 도메인의 하위 도메인이다.
  2. AA 도메인에서 B 사이트에서 제공하는 기능을 이용해 공통 기능을 구현하였다.
  3. BA 도메인에서 AA 도메인의 기능을 이용하기 위해 AA 도메인에서 제공하는 웹 페이지를 팝업으로 실행한다.
  4. AA 도메인에서는 기본 설정을 잡고, B 도메인의 페이지를 호출한다.
  5. B 도메인에서는 기능을 모두 수행하고 그 결과를 AA 페이지에 반환한다.
  6. AA 도메인의 결과 페이지에서는 최종 결과를 팝업을 실행한 BA 도메인 페이지로 전달한다. 이 전달을 위해 일반적으로 widnow.opener를 사용한다. 보통은 window.opener.location.replace(…) 메소드를 활용해서 Opener 페이지를 다른 페이지로 redirection 시키는 방법이 적용된다.(물론 우리도 이런 방법을 사용했다.)

설명은 복잡하지만 아래 그림을 보면 좀 더 이해가 빠를 것이다.

일반적인 시나리오고, 대부분(?)의 경우에 이 방식은 정상적으로 잘 동작한다. 하지만 IE가 이 대부분의 경우에 포함되지 않는 것 같다.
IE는 마지막 5번 과정에서 팝업을 실행시킨 페이지가 지정된 페이지로 redirection되지 않는다. 기존 화면은 그대로 유지된 상태에서 새로운 탭 화면에서 replace() 메소드로 전달된 url이 나타난다. OMG

재미있는 건 이 현상은 크롬이나 파이어폭스에서는 나타나지 않는다. 오직 IE10, IE11등 IE 브라우저에서만 나타난다. IE에서 당췌 뭔 짓을 한거야???

문제를 좀 파보다보니 다음 문제 사항을 찾게 됐다.
팝업 혹은 frame, iframe 환경에서 서로 다른 도메인간에 데이터를 주고 받는 건 위험하다.
따라서 이걸 위한 적절한 안전 장치가 필요하다.
각 브라우저에 따라 안정 장치를 구현하는 방법이 틀린데 그럼 IE는 이걸 어떤 방식으로 구현했을까?

팝업된 화면에서 페이지 navigation등이 발생해서 opener와 다른 도메인으로 callee 화면이 이동된 경우, window.opener에 대한 callee쪽에서 호출하는 것을 차단한다.

그럼 어떤 방식으로 해야 callee쪽에서 호출했을 때 caller쪽의 페이지를 접근할 수 있는걸까? 여러 방법을 찾아봤지만, 뾰족한 방법이 보이지 않았는데 찾다보니 내부 사이트에 다음과 같은 코드가 존재하는 걸 확인했다.

document.domain

즉, document.domain의 값을 caller와 callee 사이에 맞추면 된다.  실행시킨 화면과 팝업 화면을 나타내는 document의 domain이 동일한 값을 가지면 document.location의 값을 참조하거나 replace() 등의 함수를 사용해서 변경할 수 있다. 하지만 그렇다고 아무 도메인 값을 document.domain 객체 값에 할당할 수 있는 것은 아니다. 현재 도메인이 sub.a.b.c 라고 한다면 document.domain의 값이 될 수 있는 대상자는 a.b.c, b.c 등이 될 수 있다. 아예 다른 도메인으로의 변경은 데이터의 hijacking을 고려해서 허용되지 않는 것 같다.

이 방식을 적용해서 위 그림의 시나리오를 정리해보면 아래와 같은 그림으로 풀어볼 수 있다.

 

  • AA 화면에서 “Click here to popup” 링크가 눌렸을 때 현재 화면의 document.domain의 값을 A.com 으로 JS로 변경한다.
  • 팝업 화면은 Redirection 혹은 내부 페이지 이동을 통해 각 페이지의 hostname이 domain 값이 된다.
  • 팝업의 최종 화면인 end.B.A.com에서 화면을 닫기 전에 A.com 값으로 팝업 페이지의 document.domain 값을 변경한다.  end.B.A.com 도메인의 상위 도메인인 A.com으로 값을 변경하는 것이기 때문에 보안적으로 허용된다.
  • 팝업 화면과 팝업 화면을 실행시키는 화면의 도메인이 이제 A.com 으로 동일해졌다. 이 시점부터 팝업 화면에서 실행 화면의 페이지를 window.opener 객체를 이용해서 제어할 수 있는 길이 생겼다.
  • 이 상태에서 Opener 페이지를 이동시키고, 팝업 화면은 닫히면 된다!!!

보안이라는 관점에서 보면 되려 이런 고려는 오히려 크롬이나 파이어폭스보다 IE가 좀 더 나은거 아닌가 하는 생각도 든다. (하지만 이런 정책이 있다는게 어딘가에 알려졌다면 더 좋았겠지만, 당췌 이 정보를 찾기가 넘 어렵다는게 함정!!!)

암튼 이렇게 해서 문제를 해결해서 어색한 동작을 없앴다라는게 기쁠 뿐이다.