지긋지긋한 CORS 파헤쳐보자

김재민·2019년 11월 7일
17

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

URLisSameWhy?
http://store.company.com/dir2/other.htmlTruePath만 다르기 때문에
http://store.company.com/dir/inner/another.htmlTruePath만 다르기 때문에
https://store.company.com/page.htmlFalse프로토콜이 다름
http://store.company.com:81/dir/page.htmlFalsePort가 다름
http://news.company.com/dir/page.htmlFalse호스트가 다름

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

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번으로 진행하시는게 속이 편하실껍니다.

profile
Front end

0개의 댓글