CORS (Cross Domain)

서버와의 통신을 위해 ajax나 XMLHttpRequest를 사용하다보면 CORS 에러가 나오는 경우가 종종 발생합니다.
할때마다 설정 방법이나 우회 방법을 항상 찾다보니 매번 고생하는거 같아 정리해봅니다.

CORS 란?

CORS는 Cross-Origin Resource Sharing의 약자로 보안상의 이유로, 브라우저들은 스크립트 내에서 초기화되는 cross-origin HTTP 요청을 제한합니다. 예를 들면 다음과 같습니다.

    # 사이트 도메인이 www.a.com 일 경우
    const xhr = new XMLHttpRequest();
    xhr.onreadystatechange = () => {
        if (xhr.readyState === xhr.DONE) {
            if (xhr.status === 200 || xhr.status === 201) {
                console.log(xhr.responseText);
            } else {
                console.error(xhr.responseText);
            }
        }
    };
    xhr.open('get', 'https://www.b.com/api/v1/user/13');
    xhr.send();

위 예제에서 사이트의 도메인은 www.a.com인데 Ajax를 할 경우 www.b.com처럼 다른 도메인에 보낼 경우 CORS 관련 에러가 납니다.
아래는 Same-origin이 되는 조건에 대해서 보여줍니다. (참고 : https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy)

기준 url : http://store.company.com/dir/page.html

URL isSame Why?
http://store.company.com/dir2/other.html True Path만 다르기 때문에
http://store.company.com/dir/inner/another.html True Path만 다르기 때문에
https://store.company.com/page.html False 프로토콜이 다름
http://store.company.com:81/dir/page.html False Port가 다름
http://news.company.com/dir/page.html False 호스트가 다름

아래는 각 브라우저에서 보여지는 에러 문구들 입니다.

Chrome
Access to XMLHttpRequest at '{target url}' from origin '{current url}' has been
 blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present 
on the requested resource.

Firefox
교차 출처 요청 차단: 동일 출처 정책으로 인해 {target domain}에 있는 
원격 자원을 차단하였습니다. (원인: CORS 요청이 성공하지 못함)

Safari
[Error] Origin {current url} is not allowed by Access-Control-Allow-Origin.
[Error] XMLHttpRequest cannot load {target url} due to access control checks.
[Error] Failed to load resource: Origin {current url} is not a
llowed by Access-Control-Allow-Origin. (13, line 0)

IE

CORS 해결하기

검색을 해보면 다음과 같은 방법들이 나옵니다.

jsonp(json with padding)를 통한 해결

  • JSONP는 HTML의 script 요소로부터 요청되는 호출에는 보안상 정책이 적용 안되는 것을 이용한 우회 방법입니다.
  • jQuery에서 ajax 사용시 type에 jsonp로 요청하면 됩니다.
  • 단점으로는 GET방식에서만 사용 가능합니다.

Proxy 서버를 두는 방법

  • 중간에 Proxy 서버를 두는 것인데 솔직히 이 방법으로 할 바에는 서버 설정 건드는게 좋다고 생각합니다.

jquery.ajaxPrefilter() 사용 방법

  • 1번에서 써던 방식과 흡사하지만 ajax에는 json으로 설정해두고 통신할때 prefilter에서 jsonp로 속여서 보내는 방식
  • jQuery 1.5 이상에서 crossDomain 옵션도 true로 설정해줘야 합니다.

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

  • apache

    • httpd.conf에서 mod_headers.c 쪽에 설정을 넣어주면 됩니다.

    • 또는 VirualHost 부분에 넣어도 됩니다.

        <IfModule mod_headers.c>
           Header set Access-Control-Allow-Origin "*"
        </IfModule>
  • nginx

    • nginx.conf 파일 안에 location / 부분에 add_header로 넣어주면 됩니다.

      location / {
          #root   html;
          root e:/;
          add_header 'Access-Control-Allow-Origin' '*';
          index  index.html index.htm;
      }
  • AWS

    • S3

      • S3같은 경우는 권한 부분에 CORS 설정 하는 부분이 있습니다. 그곳에 다음과 같이 설정 하시면 됩니다.

        <CORSConfiguration>
         <CORSRule>
           <AllowedOrigin>http://www.example1.com</AllowedOrigin>
        
          <AllowedMethod>GET</AllowedMethod>
           <AllowedMethod>PUT</AllowedMethod>
           <AllowedMethod>POST</AllowedMethod>
           <AllowedMethod>DELETE</AllowedMethod>
        
           <AllowedHeader>*</AllowedHeader>
         </CORSRule>
        </CORSConfiguration>
    • CloudFront

      • CloudFront는 Behavior 부분에서 Cache Based on Selected Request Headers을 whitelist로 변경 후
        아래 whitelist에서 Origin을 추가해주면 됩니다.

위 4가지를 알아보았습니다만 가장 간편하면서 명확한 방법은 4번입니다.
1, 2, 3번을 하기 전에 4번이 가능하다면 4번으로 진행하시는게 속이 편하실껍니다.