CORS(Cross-Origin-Resource-Sharing)

김우진·2021년 11월 1일
0

network

목록 보기
6/8

들어가기 전

이 글은 스파르타 내일 배움 캠프의 저희 조 팀원이신 하림님이 정리한 글과 MDN 공식 문서 CORS와 SOP 부분, 그 외 다른 블로그들을 참조하여 작성하였습니다.

URL Origin

Origin 키워드는 다양하게 사용되므로 정확한지 않겠지만 여기서 사용하는 Origin은 URL과 관련되어 있으므로 URL Origin이라 칭하겠습니다.

URL의 구성
https://www.test.com:80/test/detail?data=1

  • https : Protocol
  • www.test.com : Host
  • 80 : Port
  • test/detail : Path
  • data=1 : Query String

URL 에서 말하는 origin은 위의 url 구성요소 중 protocol, host, port를 합친 것을 말한다. 브라우저 콘솔창에서 location.origin 명령어를 통해서 현재 페이지의 origin을 확인할 수 있다.

출처?

Cors를 다룬 대부분의 글을 보면 출처라는 단어가 나온다. 이 출처는 무슨 말일까?
여기서 말하는 출처는 위에서 설명한 Origin을 기준으로 나뉜다.
Origin이 같으면 같은 출처라 하고, Protocol, Port, Host 중 하나라도 다르면 다른 출처라고 인식한다.

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

자바스크립트 엔진 표준 스펙의 보안 규칙으로 하나의 출처에서 로드된 자원(문서 or 스크립트)이 호스트나 프로토콜, 포트번호가 일치하지 않는 자원과 상호작용 하지 못하도록 요청 발생을 제한하고, 동일 출처에서만 접근이 가능한 정책이다.

즉, 동일 출처 정책이란 같은 Origin 출처의 서버로만 요청을 주고 받을 수 있다는 것이다. 여기서 말하는 Origin 출처란 요청을 보낸 도메인을 의미한다.

  • http://www.same-domain.com --> http://www.same-domain.com = same-origin
  • http://www.same-domain.com -/-> http://www.cross-domain.com = cross-origin

이 정책으로 인해서 XSS, XSRF 같은 보안 취약점 공격을 잘 막아주지만 웹 페이지가 발전하면서 API를 통해 외부 리소스에 접근하는 경우가 많아지고, 클라이언트와 서버를 분리하여 개발하는 경우도 늘어나면서 CORS와 관련된 문제가 발생하기 시작했다.

CORS(Cross-Origin-Resource-Sharing)

Cross-Origin으로 리소스에 접근하는 것은 동일 출처 정책을 위반 하므로 보안상의 이유로 Client 측에선 이를 거부한다. 웹 애플리케이션은 자신의 출처와 동일한 리소스만 불러올 수 있으며, 다른 출처의 리소스를 불러오려면 그 출처에서 Response Header에 올바른 CORS 헤더를 포함해 반환해야 한다. 즉, CORS란 출처가 다른 도메인에서의 AJAX요청이라도 서버 단에서 데이터 접근 권한을 허용하는 정책이다.

CORS의 핵심 개념은 Client측에서 거부하는 것이다. 서버는 CORS를 위반해도 응답은 해준다. 이를 막기 위해서 preflight 방식을 통해 본 요청을 보내기전 OPTIONS 요청을 통해 요청의 유효성을 검사해 Client, Server 모두 만족할 만한 통신방식을 사용한다.

Client 측에선 유효한 요청인지 진짜 데이터를 보내기전 간편히 알아볼 수 있고,(성능 상의 이점) Server 측에선 자신의 리소스를 주지 않아도 된다.

Server 측 해결 방법

1. Access-Control-Allow-Origin response header

가장 많이 알려진 방법으로 Access-Control-Allow-Origin을 통해 응답 헤더에 주어진 Origin으로부터 요청 코드와 공유될 수 있는 지 확인한다. 서버측 response에서 접근 권한을 주는 헤더를 추가해 CORS 에러를 해결하는 방법이다. 우리 수업에서도 이 방법을 통해서 문제를 해결하였다.

'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS,POST'

각 언어에 맞게 response의 header에 저 코드만 추가 해주면 되므로 비교적 간단한 방법이지만 이 방법은 접근 권한을 허용하는 모든 요청의 응답에 추가해주어야 하므로 만약 모든 요청에 권한 허용을 한다면 모든 응답 전에 위의 헤더를 추가해야 한다는 번거로움이 있다.

2. 미들웨어 CORS

응용 소프트웨어가 운영체제로부터 제공받는 서비스 이외에 추가적으로 이용할 수 있는 서비스를 제공하는 컴퓨터 소프트웨어인 미들웨어를 사용하는 방법이다. 이 글에선 Node.js Express를 미들웨어로 사용하는 방법에 대해서 기술한다.

  1. 아래 명령어를 통해서 cors와 관련된 패키지를 설치 해준다.
    npm i cors --save

  2. Node.js Express 공식문서를 참조하여 서버를 구현하고 App.js 파일에 미들웨어를 연결한다.

    const express = require('express');
    const cors = require('cors');
    const app = express();
    
    app.use(cors());
  3. 위와 같이 아무런 옵션없이 app.use(cors());로 설정하면 모든 cross-origin 요청에 대해 응답을 주므로, 특정 도메인 요청만 받아야 하는 경우는 아래와 같이 설정해준다.

    const corsOptions = {
      origin: 'http://test.com', // 허용해줄 domain
      credentials: true, // response header에 Access-Control-Allow-Credentials 추가해줌
      optionsSuccessStatus: 200 
    };
    
    app.use(cors(corsOptions));

클라이언트 측 해결 방법

만약 직접 구현한 서버가 없어 클라이언트 내에서만 해결해야 할 경우 사용하는 방식이다.

1. Proxy 설정

Proxy는 직접 통신하지 못하는 두 개의 컴퓨터 사이에서 서로 통할 수 있도록 돕는 역할을 하는 서버이다.
이 Proxy 서버가 클라이언트 - 서버 중간에서 요청을 받아 Access-Control-Allow-Origin 헤더를 추가해주는 방법으로 해결할 수 있다.

P.S.

미들웨어, proxy, preflight에 관해선 정리되는 대로 올리겠습니다ㅠㅠ

출처

  1. yejinh님의 velog : Same-Origin Policy 동일 출처 정책과 CORS 에러
  2. MDN Web Docs : 교차 출처 리소스 공유 (CORS)
  3. MDN Web Docs : 동일 출처 정책
  4. xiubin님의 blog : 나를 너무나 힘들게 했던 CORS에러 해결하기
  5. 코병아리님의 blog(스파르타 내일배움 캠프 같은 팀원) : 진짜 초보를 위한 CORS 정리

0개의 댓글