CORS

Youn·2021년 5월 29일
2

WEB

목록 보기
1/4
post-thumbnail

CORS (Cross-Origin Resource Sharing)

도메인, 또는 포트가 다른 서버의 자원을 요청하는 매커니즘

CORS의 Origin

  • URL (서버의 위치)
    • Protocol + Host + Port Number(:80, :443) -> 출처
    • port number 는 생략 가능 (HTTP:80, HTTPS:443 으로 기본적으로 정해져 있기 때문)

CORS Error

보안상의 이유로, 브라우저는 스크립트에서 시작한 CORS 요청을 제한한다.

SOP(Same-Origin Policy)

  • ❗ 같은 출처에서만 리소스를 공유할 수 있다
  • 하지만, CORS 정책을 지킨 리소스 요청에 대해 예외 조항을 두고 허용하기로 함
  • CSRF(Cross-Site Request Forgery)XSS(Cross-Site Scripting) 위험을 줄이고자 함
  • 출처 비교 : 브라우저에 구현되어 있는 스펙
    • CORS 를 위반하더라도 서버는 정상적으로 응답, 응답의 파기 여부는 브라우저가 결정

⭐ CORS 동작

Simple Request -> Preflight 를 트리거하지 않는 일부 요청
Preflight Request -> 사전 전송, 안전한지 확인
Credential Request -> 인증정보를 포함한 요청

  • 웹 클라이언트 어플리케이션이 다른 출처의 리소스를 요청할 때는 HTTP 프로토콜 사용

1) 브라우저 : 요청 헤더에 Origin 이라는 필드에 요청을 보내는 출처를 함께 담아 보냄
Origin : https://velog.io/
2) 서버 : 해당 요청에 대한 응답시 응답 헤더의 Access-Control-Allow-Origin 이라는 필드에 리소스를 접근하는 것이 허용된 출처를 내려줌
3) 브라우저 : 보냈던 요청의 Origin과 서버가 보내준 응답의 Access-Control-Allow-Origin를 비교하여 유효성 체크

Simple Request (단순 요청)

  • 조건
    • GET / HEAD / POST 중 하나의 메서드
    • 설정가능헤더
      • Accept
        - Accept-Language
        - Content-Language
        - Content-Type (application/x-www-form-urlencoded,multipart/form-data, text/plain 만 가능!)
        - DPR
        - Downlink
        - Save-Data
        - Viewport-Width
        - Width
    • 요청에 사용된 XMLHttpRequestUpload 객체에는 이벤트 리스너가 등록되어 있지 않음
      XMLHttpRequest.upload 프로퍼티를 사용하여 접근
    • 요청에 ReadableStream 객체가 사용되지 않음
  • 브라우저 -> 서버

    GET /resources/public-data/ HTTP/1.1
    Host: bar.other
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
    Accept-Language: en-us,en;q=0.5
    Accept-Encoding: gzip,deflate
    Connection: keep-alive
    Origin: https://foo.example

  • 서버 -> 브라우저

    HTTP/1.1 200 OK
    Date: Mon, 01 Dec 2008 00:23:53 GMT
    Server: Apache/2
    Access-Control-Allow-Origin: * // 모든 도메인에서 접근할 수 있음
    Keep-Alive: timeout=2, max=100
    Connection: Keep-Alive
    Transfer-Encoding: chunked
    Content-Type: application/xml

    […XML Data…]

Preflight Request


Access-Control-Request-* 는 실제 POST 요청에서는 사용되지 않음!!

  • 먼저 OPTIONS 메서드를 통해 다른 도메인의 리소스로 HTTP 요청을 보내 실제 요청이 전송하기에 안전한지 확인

  • Cross-site 요청은 유저 데이터에 영향을 줄 수 있기 때문에 이와같이 미리 전송(preflighted)하는 것

  • 동작 예시
    1) 사용자가 js 의 fetch API 로 브라우저에게 리소스를 받아오라는 명령 내림
    2) 브라우저 -> 서버 : 예비 요청

    OPTIONS /resources/post-here/ HTTP/1.1
    Host: bar.other
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
    Accept-Language: en-us,en;q=0.5
    Accept-Encoding: gzip,deflate
    Connection: keep-alive
    Origin: http://foo.example
    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: X-PINGOTHER, Content-Type

    • Origin 에 대한 정보 + 이후 보낼 본 요청에 대한 정보
    • Access-Control-Reqeust-Headers : 본 요청에서 사용할 Headers
      Access-Control-Request-Method : 본 요청에서 사용할 Method

    3) 서버 -> 브라우저 : 예비 요청에 대한 응답으로 자신이 허용, 금지하고 있는 것들에 대한 정보를 응답 헤더에 담아서 보내줌

    HTTP/1.1 204 No Content
    Date: Mon, 01 Dec 2008 01:15:39 GMT
    Server: Apache/2
    Access-Control-Allow-Origin: https://foo.example
    Access-Control-Allow-Methods: POST, GET, OPTIONS
    Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
    Access-Control-Max-Age: 86400
    Vary: Accept-Encoding, Origin
    Keep-Alive: timeout=2, max=100
    Connection: Keep-Alive

    • Access-Conrol-Allow-Origin : 해당 리소스에 접근 가능한 출처
    • 요청한 Origin 과 다를 경우, CORS 정책을 위반했다고 판단
    • 판단 시점은 예비 요청에 대한 응답을 받은 이후이기 때문에 예비 요청의 성공 여부와는 상관X

    4) 브라우저 : 보낸 예비 요청과 서버에서 받은 허용 정책 비교 후, 요청 안전 판단 -> 안전하다면 같은 엔드포인트로 본 요청을 보냄

    5) 서버 : 본 요청에 대한 응답
    6) 브라우저 : 최종적으로 해당 응답 데이터를 js 에게 넘겨줌

Credential Request

  • HTTP cookies 와 HTTP Authentication 정보를 인식
  • 기본적으로 cross-site XMLHttpRequest 나 Fetch 는 자격증명을 보내지 않고 좀 더 보안을 강화하고 싶을 때 사용함
  • 인증과 관련된 정보를 담을 수 있게 해줌
  • credentials 옵션
    • same-origin (기본값) : 같은 출처 간 요청에만 인증 정보를 담을 수 O
    • include : 모든 요청에 인증 정보를 담을 수 O
    • omit : 모든 요청에 인증 정보를 담지 X
  • CORS 정책 위반 검사 추가되는 룰
    1) Access-Control-Allow-Origin에는 *를 사용할 수 없으며, 명시적인 URL이어야한다.
    2) 응답 헤더에는 반드시 Access-Control-Allow-Credentials: true가 존재해야한다.

CORS 에러 해결

webpack dev server

webpack-dev-server 라이브러리의 프록시 기능 사용

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'https://api.evan.com',
        changeOrigin: true,
        pathRewrite: { '^/api': '' },
      },
    }
  }
}
  • 로컬환경에서 localhost 로 api 를 보내더라도 웹팩이 뒤에서 요청을 프록싱 해줌

Node.js

서버에서 cross-origin HTTP 요청 허가

1) Access-Control-Allo-Origin response 헤더 추가

  app.get('/data', (req, res) => {
    res.header("Access-Control-Allow-Origin", "*");
    res.send(data);
  });

2) node.js 의 미들웨어 CORS 추가 패키지참고

  npm install --save cors 
  yarn add cors
  
  /* 모든 요청에 대한 허가 - 보안 취약 가능성*/
  const express = require('express');
  const cors = require('cors');

  const app = express();

  app.use(cors()); // CORS 미들웨어 추가

  /* CORS 옵션 설정 */
  const corsOptions = {
    origin: 'http://localhost:3000', // 허락하고자 하는 요청 주소
    credentials: true, // true -> 설정한 내용을 response 헤더에 추가
  };

  app.use(cors(corsOptions)); // config 추가

Extension 개발

크롬 익스텐션 / Whale 익스텐션 개발시 api 요청을 해야 할 때 겪은 에러
깃헙이슈기록 참고

  • manifest 파일에 permission 값을 추가해주면 된다
{ 
  ...
  "permissions":[
    "http://www.google.com/",
    "https://www.google.com/"
  ],
  ...
}

profile
youn

0개의 댓글