반응형

[ Javascript ] 자바스크립트 ajax 크로스도메인 이슈(CORS)

특정 서버의 API를 테스트해야하는 페이지를 작업중 크로스도메인 이슈에 맞닥뜨리게 되었다.
예전 고객센터시스템 개발할 때 자주접하던 이슈였기에 쉽게 해결할 수 있을 줄 알았으나....꽤나 삽질을 많이 했다.
그래서 겸사겸사 정리하며 다시 한 번 머리에 각인!

1. 크로스도메인이슈 (CORS, Cross Origin Resources Sharing)

jQuery 1.5.0이후 버전부터는 이러한 crossdomain을 원천 봉쇄해버렸다.
테스트페이지(웹) -> 쿠키매칭시스템API호출
 http://alpha-adserver.toast.com/ -> http://cm-exchange.toast.com

크로스 도메인은 서로 다른 도메인 간 호출로 위와 같이 호출하게되면 크로스도메인이슈가 발생하게 된다.
보통 서브도메인만 다른 경우의 사이트끼리의 정보 교환은 document.domain만 맞추어 주면 해결이 가능하다.
ex)
1. abc.toast.com
2. def.toast.com
사이트끼리의 정보 교환은 해당페이지 스크립트에 document.domain='toast.com' 설정시 해결가능

하지만 이번 경우에는 브라우져 -> 서버간의 호출로 다음과 같은 문제로 해결이 힘든 상황.
따라서 javascript, ajax로 요청시 다음과 같은 에러가 발생
스크린샷 2018-07-25 오후 5.16.21.png
이렇게 외부로 요청이 안되는 것은 자바스크립트 엔진 표준 스펙의 동일 출처 정책(SOP, Same-Origin Policy)이라는 보안 규칙이 있기 때문


2. 동일 출처 정책 (SOP, Same-Origin Policy)

웹어플리케이션 보안 모델에서 중요한 개념중 하나
해당 정책으로 인해 자바스크립트(XMLHttpRequest)로 다른 웹페이지 접근시 같은 출처(same origin)의 페이지에만 접근 가능하다.
같은 출처라는 것은 Protocol, Host명, Port가 같다는 것을 의미
쉽게 말해, 웹페이지의 스크립트는 그 페이지와 같은 서버에 있는 주소로만 ajax요청을 할 수 있다는 것이다.
스크린샷 2018-07-25 오후 5.19.29.png


3. CORS 작동 방식

스크린샷 2018-07-25 오후 5.21.56.png
Preflight request(사전요청) - 요청하려는 URL이 외부 도메인일 경우 웹 브라우저는 preflight요청을 먼저 날린다.
preflight요청은 실제로 요청하려는 경로와 같은 URL에 대해 OPTIONS 메서드로 요청을 미리 날려보고 요청 할 수 있는 권한이 있는지 확인한다.
CORS요청을 편법없이 처리하기 위해서는 클라이언트 처리만으로는 어렵고 서버측에서 preflight요청을 처리하는 기능이 필요하다.


4. CORS 해결할 수 있는 방법.

1) 웹 브라우저 실행옵션이나 플러그인인을 통한 동일출처 정책 회피(크롬 --disable-web-security옵션을 추가하여 실행)

-> 테스트하는 컴퓨터마다 설정해야하는 번거로움으로 X

2) jsonp(json with padding)를 통한 해결

JSONP는 HTML의 script 요소로부터 요청되는 호출에는 보안상 정책이 적용되지 않는다는 점을 이용한 우회 방법
다시 한번 확실히 하자면, script 요소는 src를 호출한 결과를 javascript를 불러와서 포함시키는 것이 아니고 실행시키는 태그입니다.

다음과 같이 dataType만 변경해서 보내면된다??? nono 서버에서 수정해줘야 함...(일반적인 웹사이트에서는 dataType만 jsonp로 고치면 된다는 식으로 말하고있음...)

$.ajax({
    type: 'GET',
    url: url,
    dataType: 'jsonp',   //cross-domain 이슈를 회피하기 위해 jsonp요청을 한다.
    success: callback    //callback이란 함수를 나의 success function에 매핑시켜 콜백요청을 처리할 것이다.
});

or

$.getJSON(url + "?callback=?", data, callback);</span>

RESPONSE의 경우
callback({'kingbbode', age:28})

이처럼 Callback 함수명으로 감싸져서 오는데 서버에서 위와같이 감싸진 형태의 Text로 내려주어야한다!!!!
Text로 내려진 데이터가 Javascript로 실행되는 과정을 Jquery에서 지원하여 Success 함수로 연결시켜 주는 것이다.

정확한 서버구현과 내용은 참고 : jsonp참고페이지

**-> 서버를 건드릴거면 Accss-Control-allow-origin만 설정해주는 것이 훨씬 간편... **

3) 중간에 proxy서버를 두는 방법

-> 배보다 배꼽이 더큰 상황...

4) jquery.ajaxPrefilter()

ajax요청전 내부적으로 $.ajaxPrefilter()를 거친다. 따라서 ajaxPrefilter()내부를 변조하면 cross-domain문제를 해결할 수 있다. 라는 느낌?
밑의 코드는 통신 자체를 'jsonp'로 속여 보내는 방식으로 처리가능하다고 하는데 나의 경우는 정상동작 안함...(http://igna.tistory.com/20?category=430584)

$.ajaxPrefilter('json', function(options, orig, jqXHR) {
    if (options.crossDomain && !$.support.cors) return 'jsonp'
});

$.ajax({
    type: 'GET',
    crossDomain: true,
    url: url,
    dataType: 'json',
    success: function(data, textStatus, xhr) {        $('#bidValue').val(JSON.stringify(data));
}});

5) 서버에서 Accss-Control-allow-origin 설정을 통한 요청 허용

API컨트롤러에 다음과 같은 애노테이션 선언
특정 도메인만 허용하고 싶은 경우에는 별도 config로 설정 후 사용
참고 : 스프링에서 cors설정

@CrossOrigin("*")

>> 결국에는 서버에 Accss-Control-allow-origin으로 특정 도메인을 풀어주는 것으로 해결

ref :  http://enterkey.tistory.com/409


반응형
반응형


다른 도메인 내부에 쿠키 생성하기 (이게 가능해???)


최근 쿠키매칭시스템 설계를 위해 광고 프로세스 전반에 대한 내용을 학습중 우리 도메인 쿠키 내부에 


다른 도메인 쿠키값들이 박혀있는 걸 발견하였다.


뭐야 이거 어떻게 박는거야? 크로스도메인 이슈 때문에 당연히 안될거라고 생각했었는데 심지어 여러 도메인들 쿠키값들이 박혀있었다....


위의 캡쳐화면을 보면 cloud.toast.com 페이지에 들어갔는데 toast.com쿠키 내부를 보면 .toast.com말고도 여러 도메인들의 


쿠키값들이 설정되어있는 것을 보았다.


어떻게 이게 가능하단 말인가????


근데 가능하다는거....실제로 구현을 해보고서도 좀 신기하긴했다...




방법은 다음과 같다. 


해당 페이지의 html에 다른 도메인을 호출하는 호출하는 태그를 심는다. 이 때 태그는 <img>, <a> 태그가 가능하다.


다음을 보자.


local.media.com(내가 호스트에 등록해 띄운 페이지) 도메인의 페이지 내부에는 다음과 같은 태그를 박았다.


이렇게 박았을 경우 페이지가 렌더링되는 시점에 해당 도메인의 서버에 요청이 가게 된다.


요청을 받은 해당 도메인의 서버에서 요청을 받아 내부에서 쿠키를 생성하면 다른 도메인 쿠키 내부에 본인들의 쿠키값을 설정할 수 있는 것이다.


local.toast.com:8082/dsp/request 컨트롤러에서 요청을 쿠키를 만들어주게 되면




내가 생성한 쿠키 값이 박히는걸 볼 수 있다.


만약 다른 도메인의 iframe을 박아 렌더링 하게 된다면 해당 도메인의 쿠키가 하나 더 생기게 된다.


iframe으로 local.doubleclick.com:8080/adx/request를 요청해보자


이번에는 local.media.com쿠키 내부에 값이 생성되는게 아니고 별도의 local.doubleclick.com쿠키가 생성된 것을 볼 수 있다.


물론 어떻게 쿠키를 심든간에 httpServletRequest로 request를 받아 cookie를 얻어오게되도 본인 


서브도메인에 일치하는 쿠키값만 받아올 수 있다!!!(당연당연)


반응형
반응형

 안녕하세요. 오늘은 전에 읽었던 '그림으로 배우는 HTTP&NETWORK BASIC'이라는 책을 간단히 제가 몰랐거나 나중에 다시 한 번 상기가 필요한 내용들로 정리해보려고 합니다. 아무래도 웹 개발을 하다보니 네트워크 지식들이 필요할 때가 많은데요. 중요한 내용을 바탕으로 쉽게 그림으로 잘 설명되어 있는 책을 골라 읽어보았는데 생각보다 괜찮네요. 기본적인 네트워크 지식이 필요하신 분들에게도 좋은 책이 될 것 같네요. 아무래도 제 주관적으로 중요하다 싶은 내용이나 나중에 한 번 더 봐야 될 부분들에 대해서 정리가 될 것 같은데 보시고 괜찮으시다면 책을 사셔서 보시는걸 추천 드리겠습니다.

[ TCP/IP 계층화 ]
-TCP/IP는 '애플리케이션 계층', '트랜스포트 계층(TCP)', '네트워크 계층(IP)', '링크 계층' 이렇게 총 4계층으로 나뉘어 있다.
> 계층화의 메리트는 인터넷이 하나의 프로토콜로 되어 있다면 어디선가 사양이 변경되었을 때 전체를 바꾸지 않으면 안되지만, 계층화되어 있으면 사양이 변경된 해당 계층만 바꾸면 됩니다.

[ 패킷 ]
-패킷이란 전송하는 데이터의 최소 단위 입니다.

[ IP, MAC ]
-IP(Internet Protocl)의 역할은 개개의 패킷을 상대방에게 전달하는 것. 상대방에게 전달하기까지 여러 요소가 필요한데 그 중에서도 IP와 MAC(Media Access Control Address)라는 요소가 중요하다.
IP주소는 각 노드에 부여된 주소를 가리키고 MAC 주소는 각 네트워크 카드에 할당된 고유의 주소이다. IP주소는 변경 가능하지만 기본적으로 MAC 주소는 변경 할 수 없다.

[TCP, Three way handshaking]
-TCP(Transfer Control Protocol)는 대용량의 데이터를 보내기 쉽게 작게 분해하여 상대에게 보내고, 정확하게 도착했는지 확인하는 역할을 담당한다. TCP는 상대에게 확실하게 데이터를 보내기 위해 "쓰리웨이 핸드셰이킹(three way handshaking)"이라는 방법을 사용하고 있는데 이 방법은 패킷을 보내고 나서 바로 끝내는 것이 아니라, 보내졌는지 여부를 상대에게 확인하러 간다. 이것은 'SYN'와 'ACK'라는 TCP 플래그를 사용한다. 송신측에서는 최초 'SYN'플래그로 상대에게 접속함과 동시에 패킷을 보내고, 수신측에서는 'SYN/ACK' 플래그로 송신측에 접속함과 동시에 패킷을 수신한 사실을 전한다. 마지막으로 송신측이 'ACK' 플래그를 보내 패킷 교환이 완료되었음을 전한다.

[ HTTP, STATLESS PROTOCOL ]
-HTTP는 상태를 계속 유지하지 않는 스테이트리스(stateless)프로토콜로 리퀘스트와 리스폰스를 교환하는 동안에 상태를 관리하지 않는다. HTTP에서는 새로운 리퀘스트가 보내질 때 마다 새로운 리스폰스가 생성된다. 프로토콜로서는 과거의 리퀘스트나 리스폰스 정보를 전혀 가지고 있지 않다. 이는 많은 데이터를 매우 빠르고 확실하게 처리하는 범위성(scalability)을 확보하기 위해서 이와 같이 간단하게 설계되어 있는 것이다.

[ 지속연결, 파이프라인화 ]
-HTTP/1.1와 일부 HTTP/1.0에서는 TCP 연결 문제를 해결하기 위해 지속연결(Persistent Connections)이라는 방법을 고안하였다.  지속 연결의 특징은 어느 한 쪽이 명시적으로 연결을 종료하지 않는 이상 TCP 연결을 계속 유지한다. 지속 연결은 여러 리퀘스트를 보낼 수 있도록 파이프라인(HTTP pipelining)화를 가능하게 한다. 파이프라인화에 의해서 이전에는 리퀘스트 송신 후에 리스폰스를 수신할 때까지 기다린 뒤에 리퀘스트를 발행하던 것을, 리스폰스를 기다리지 않고 바로 다음 리퀘스트를 보낼 수 있게 되었다. 지속 연결 < 파이프라인화(리퀘스트 수가 늘어날 수록 현저한 차이)

[ STATELESS PROTOCOL 이점 ]
-상태를 유지하지 않는다는 점에서 서버의 CPU나 메모리 같은 리소스의 소비를 억제할 수 있다. 또한, 단순한 프로토콜이기에 HTTP가 다양한 곳에서 이용되는 측면도 있다.

[ 쿠키 - STATELESS PROTOCOL 문제 해결 ]
-쿠키는 리퀘스트와 리스폰스에 쿠키 정보를 추가해서 클라이언트의 상태를 파악하기 위한 시스템이다.

[ 인코딩으로 전송 효율을 높이다 ]
-HTTP로 데이터를 전송할 경우 그대로 전송할 수도 있지만 전송할 때에 인코딩을 실시함으로써 전송 효율을 높일 수 있다. 전송할 때 인코딩을 하면 다량의 액세스를 효율 좋게 처리할 수 있다. 단지, 컴퓨터에서 인코딩 처리를 해야 하기 때문에 CPU 등의 리소스는 보다 많이 소비하게 된다.

[ 레인지 리퀘스트 (Range Request) ]
-다운로드 중 커넥션이 끊어지게 되면 처음부터 다시 다운로드를 해야하는 문제를 해결하기 위해 일반적인 리줌(resume)이라는 기능이 필요하게 되었다. 리줌을 통해 이전에 다운로드를 한 곳에서 부터 다운로드를 재개할 수 있다. 이 기능 실현을 위해서는 엔티티의 범위를 지정해서 다운로드를 할 필요가 있다. 이와 같이 범위를 지정하여 리퀘스트 하는 것을 레인지 리퀘스트라고 부른다.

[ 콘텐츠 네고시에이션 ]
- 서로 다른 언어를 주로 사용하는 브라우저가 같은 URI에 액세스할 때에 각각 영어판 웹 페이지와 한국어판 웹 페이지를 표시하는 구조를 콘텐츠 네고시에이션(Content Negotiation)이라고 부른다.
서버 구동형 네고시에이션(서버 측에서 리퀘스트 헤더 필드의 정보를 참고해서 자동적으로 처리하는 방식)과 에이전트 구동형 네고시에이션(브라우저에서 표시 된 선택지 중에서 유저가 수동으로 선택하는 방법)이 있다.

오늘 포스팅은 여기까지 하도록 하겠습니다. :)



반응형

+ Recent posts