CORS

Vorhandenheit ·2021년 10월 19일
0

Web

목록 보기
4/8
post-thumbnail

CORS (Cross-Origin Resource Sharing)

서로 다른 Origin에서 리소스를 공유할 수 있도록 하기 위해 내놓은 정책, 서로 다른 Origin 이라는 것은 도메인 혹은 포트가 서로 다르다는 것을 의미하므로 서로 다른 도메인 주소 사이에 데이터를 주고받을 수 있도록 하기 위한 정책

배경

SPA가 등장하면서 클라이언트와 서버의 도메인을 따로 유지해야하는 경우가 생기고, 외부 API를 앱 내에 연동하여 사용하는 경우 앱과 외부 API의 Origin이 다르기 때문에 Same-Origin Policy에 의해 리소스를 공유할 수 없는 상황이 생기게 됨

Same-Origin Policy (동일 출처 정책)
웹 브라우저 보안을 위해 프로토콜, 호스트, 포트가 동일한 서버로만 ajax요청을 주고받을 수 있도록 한 정책

Origin(출처)

여기서 출처는 scheme(protocol), host(domain), port로 구성
예시) https://www.google.com/mapls 가 있다면 protocol은 http://, host는 www.google.com, port는 :443이다.

1. CORS 동작

1) Preflight Request

이 방식은 시나리오에 해당하는 상황일 때 브라우저는 요청을 한번에 보내지 않고 예비 요청과 본 요청으로 나누어서 서버로 전송
이때 브라우저가 본 요청을 보내기 전에 보내는 예비요청을 Preflight 라고 부름
이 예비 요청에는 HTTP 메소드 중 OPTIONS 메소드가 사용된다.


1. 브라우저가 서버에게 예비 요청을 보내고

option 요청과 함께 두 개의 다른 요청 헤더가 전송됨
Access- Control-request-Method: Post //실제요청의 메서드
Access-Control-Request-Headers: X-PINGOTHER, Content-Type // 실제요청의 추가헤더
  1. 서버는 이 요청에 대한 응답으로 현재 자신이 허용하는 것에 대한 정보를 응답 헤더에 담아 브라우저에 보내주게됨
Access-Control-Allow-Origin: http://foo.example	 서버측 허가출처
Access-Control-Allow-Methods: POST, GET, OPTIONS //  허가 메서드
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type	// 서버측 허가헤더
Access-Control-Max-Age: 86400 // Prefilght 응답 캐시기간
  1. 브라우저는 예비요청과 응답을 비교한 후 요청을 보내느 것이 안전하다고 판단되면 엔드 포인트로 다시 본 요청을 보내게된다

  2. 이후 서버가 이 본 요청에 대한 응답을 하면 브라우저는 최종적으로 이 응답데이터를 자바스크립트로 넘겨준다.

2) Simple Request

Simple Request(단순 요청) 예비 요청을 보내지않고 서버에게 본 요청을 보낸 후, 서버가 이에 대한 응답의 헤더에 Access-Control-Allow-Origin과 같은 값을 보내주면 그때 브라우저가 cors 정책 위반 여부를 검사하는 방식
하지만 사용할 수 있는 조건이 있다.

조건
1. 요청의 메서드는 GET, HEAD, POST 중 하나여야함
2. Accept, Accept-Language, Content-Language, Cotent-type, DPR, Downlink, Save-Data, Viewport-Width, Width를 제외한 헤더를 사용하면 안됨
3. Content-type를 사용한 경우에는 application/x-www-form-urlencoded, multipart/form-data, text/plain만 허용

3) Credentialed Request

시나리오는 인증된 요청을 사용하는 방법으로 다른 출처간 통신에서 좀 더 보안을 강화하고 싶을 때 사용하는 방법
인증관련 헤더를 포함할 때 사용하는 요청으로 브라우저가 제공하는 비동기 리소스 요청 API인 XMLHttpRequest 객체나 fetch API는 별도의 옵션 없이 브라우저의 쿠키 정보나 인증과 관련된 헤더를 기본적으로 요청에 담지않으므로, CREDENTIALS 옵션을 변경하지않고서 cookie를 주고 받을 수 없다.

  • omit : 절대로 cookie들을 전송하거나 받지않음
  • same-origin : 동일 출처라면, user credentials을 전송
  • include : cross-origin 호출이라 할지라도 언제나 user credentials을 전송
fetch.(url, {credentials: 'include'})

해결방법

1) Access-Control-Allow-Origin 세팅

대표적 방법으로, Access-Control-Allow-Origin 헤더에 알맞은 값을 세팅해주는 것

app.use((req, res, next) => {
	res.header("Access-Control-Allow-Origin", "*"); // 모든 도메인
  	res.header("Access-Control-Allow-Origin", "https://example.com"); // 특정 도메인
});

2) cors 모듈 사용

const cors = require('cors');
const app = express();
app.use(cors());

아무 옵션없이 설정하면 모든 cross-origin 요청에 대해 응답이므로, 특정 도메인이나 특정 요청에만 응답하게 옵션을 설정하는게 좋음

  • 특정 도메인 접근허용
const options = {
  origin: "http://example.com", // 접근 권한을 부여하는 도메인
  credentials: true, // 응답 헤더에 Access-Control-Allow-Credentials 추가
  optionsSuccessStatus: 200, // 응답 상태 200으로 설정
};

app.use(cors(options));

app.get("/example/:id", cors(), function (req, res, next) {
  res.json({ msg: "example" });
});

2) Webpack Dev Server로 리버스 프록싱하기

webpakc-dev-server에 프록시 기능을 사용하면 cors정책을 우회가능

// 프록시 쓰지 않았을때
// localhost:8080(클라이언트 측) --X (CORS)--> domain.com (서버 측)
// 프록시를 설정 후
// localhost:8080(클라이언트 측) --O 프록시가 설정된 Webpack Dev Server--> domain.com (서버 측)
module.exports = {
  devServer: {
    proxy: {
      "/api": {
        target: "domain.com",
        changeOrigin: true,
      },
    },
  },
};

3) package.json에 proxy 값을 설정

create-react-app 으로 생성한 프로젝트에서는, package.json 에 proxy 값을 설정하여 proxy 기능을 활성화 하는 방법도 있다.

{
    //...
    "proxy": "http://localhost:4000"
}
profile
읽고 기록하고 고민하고 사용하고 개발하자!

0개의 댓글