[웹] CORS

Woonil·2025년 6월 9일
1

목록 보기
6/6

CORS(Cross-origin Resource Sharing, 교차 출처 자원 공유)는 서로 다른 출처(origin) 간에 리소스를 공유할 수 있도록 하는 정책을 말한다. 이는 웹 브라우저 기반 보안 메커니즘으로 메인 origin을 방문하는 동안 다른 origin에 대한 요청을 허용하거나 거부할 수 있게 한다.

  • 배경: 웹 생태계가 다양해지면서 여러 서비스들 간 자유로운 데이터 송수신이 이루어질 필요가 생겼다. 이로 인해 합의된 출처들 간에 데이터 송수신을 합법적으로 허용해주기 위해, 기준을 충족하면 리소스 공유가 이루어질 수 있게 되었다.
    • 조건: 요청을 받는 백엔드 쪽에서 리소스 공유를 허락할 다른 출처들을 미리 명시해야 한다.
  • origin: 웹 콘텐츠의 출처(origin)는 접근할 때 사용하는 URL의 스킴(프로토콜), 호스트(도메인), 포트로 정의되며, 두 객체의 스킴, 호스트, 포트가 모두 일치하는 경우 같은 출처를 가졌다고 할 수 있다.
    [출처 - MDN Web Docs 용어 사전: 웹 용어 정의 | MDN]
  • SOP(Same origin Policy): 서로 다른 출처 간 리소스를 공유하지 않는 브라우저 정책으로, 기본적으로 브라우저는 최초의 정적 파일을 렌더링한 웹 서버를 origin으로 정의하게 된다. 따라서 해당 origin에서 제공되지 않은 리소스는 차단한다. SOP는 악성 사이트에서 임의로 다른 origin의 서버로 요청을 보내거나 응답에 접근하는 것을 막아, CSRF 공격을 어느정도 무력화해준다. 이렇듯 SOP는 보안을 강화하지만, 합법적인 요청까지 차단되는 비효율성이 초래될 수 있다(CORS의 등장 배경과 연결됨).

🤔개념

과정

  1. 내가 만든 사이트에서 네이버 지도 API로 요청을 보낸다. (Cross-origin 요청)

    크로스 origin 요청 시, 브라우저는 항상 origin 이라는 헤더를 요청에 추가한다.

  2. 브라우저는 요청에 origin이라는 헤더를 추가한다.

  3. 요청을 받은 네이버 지도 API 서버는 응답 헤더에 지정된 Access-Control-Allow-origin 정보를 실어서 보낸다.

  4. 브라우저는 2의 origin에서 보낸 출처값이 서버 응답 헤더에 담긴 Acess-Control-Allow-origin에 똑같이 있으면, 안전한 요청으로 간주하며 응답 데이터를 받아온다.

👌안전한 요청

  • 구성
    • 안전한 메서드: GET, POST, HEAD를 사용한 요청
    • 안전한 헤더: 기본적으로 다음과 같은 응답 헤더가 ‘안전한’ 헤더로 취급된다. ex) Accept / Accept-Language / application/x-www-form-urlencoded , multipart/form-data , text/plain 인 Content-Type / Cache-Control / Content-Language / Content-Type / Expires / Last-Modified / Pragma
  • Access-Control-Allow-origin : 서버는 요청 헤더에 있는 origin 을 검사하고, 요청을 받아들이기로 동의한 상태라면 특별한 헤더(Access-Control-Allow-origin)를 응답에 추가한다.
    1. 브라우저는 크로스 origin 요청 시 origin 에 값이 제대로 설정되어 전송되었는지 확인한다.
    2. 브라우저는 서버로부터 받은 응답 중 Access-Control-Allow-origin 이 있는지 확인하여 서버가 크로스 origin 요청을 허용하는지 확인한다.
    3. 요청 허용 시, 자바스크립트를 사용(fetch 등)하여 응답에 접근이 가능해진다. (아니라면 에러 발생)
  • Access-Control-Expose-Headers : 자바스크립트 접근을 허용하는 안전하지 않은 헤더 목록이 담기며, 클라이언트가 다른 헤더에 접근할 수 있도록 하려면 서버는 이 헤더를 사용하여 헤더를 나열해야 한다. 사용자 지정 헤더를 추가로 표시하려면 여러 헤더를 콤마로 구분하여 지정할 수 있다.

🫸안전하지 않은 요청(안전한 요청이 아닌 요청)

특별한 방법을 사용하지 않고도, <form> 이나 <script> 를 사용해 요청을 생성할 수 있다.


[출처: https://ko.javascript.info/fetch-crossorigin]

  • preflight 요청: 시간이 지나고 개발자가 자바스크립트를 사용해 안전하지 않은 요청을 보낼 수 있게 되었다. 브라우저는 안전하지 않은 요청을 서버에 전송하기 전에 preflight 요청을 먼저 전송해 서버가 크로스 origin 요청을 받을 준비가 되어 있는 지를 확인하게 되었다. 즉, 서버에 바로 요청을 보내지 않고 사전 요청을 서버에 보내 권한이 있는 지를 확인하는 과정을 거치게 된 것이다. 이후 안전한 요청과 동일한 과정으로 데이터를 주고 받기 시작한다. OPTIONS 메서드를 사용하고 두 헤더가 함께 들어가며 본문은 비어있다.
    • Access-Control-Request-Method: 안전하지 않은 요청에서 사용하는 메서드 정보를 담은 헤더
    • Access-Control-Request-Headers: 안전하지 않은 요청에서 사용하는 헤더 목록(여러 개일 경우 쉼표로 구분)을 담은 헤더
    • 응답 헤더
      • Access-Control-Allow-origin: 허용하는 origin
      • Access-Control-Allow-Methods: 허용된 메서드 정보
      • Access-Control-Allow-Headers: 허용된 헤더 목록
      • Access-Control-Max-Age: 퍼미션 체크 여부를 몇 초간 캐싱해 놓을 지를 명시하며, 브라우저는 일정 기간 동안 preflight 요청을 생략하고 안전하지 않은 요청을 보낼 수 있게 된다.

자격 증명

자바스크립트로 크로스 origin 요청 시, 브라우저는 기본적으로 쿠키나 HTTP 인증과 같은 자격 증명을 함께 전송하지 않는다. 왜냐하면 그렇게 할 경우, 사용자 동의 없이 자바스크립트로 민감한 정보에 접근할 수 있게 되기 때문이다. HTTP 요청의 경우 대부분 쿠키와 함께 전송되지만, 자바스크립트를 사용해 만든 크로스 origin 요청은 그렇지 않다. 따라서 서버가 이를 허용하기 위해서는 자격 증명이 담긴 헤더를 명시적으로 허용하겠다는 세팅을 해야 한다.

  • 과정
    1. 클라이언트에서 credentials: "include" 옵션 추가 후 요청

      fetch('http://another.com', {
        credentials: "include"
      });
    2. 서버에서 Access-Control-Allow-Credentials: true 헤더 추가 후 응답

      200 OK
      Access-Control-Allow-origin: https://javascript.info
      Access-Control-Allow-Credentials: true

      자격 증명이 함께 전송되는 요청을 보낼 땐 Access-Control-Allow-origin에 *을 쓸 수 없다. ⇒ 어떤 origin에서 요청이 왔는지에 대한 정보를 서버가 신뢰할 수 있다.

참고 자료

웹개발 짜증유발자! CORS가 뭔가요?
CORS
교차 출처 리소스 공유 (CORS) - HTTP | MDN

profile
프론트 개발과 클라우드 환경에 관심이 많습니다:)

0개의 댓글