CORS

1. CORS의 역할

동일 출처 정책으로 인해, 자사의 웹 애플리케이션이나 CDN과 같은 믿을 수 있는 출처에서도 제한이 있을 수 있습니다. 이를 해결하기 위해 CORS라는 기술이 사용됩니다.

CORS (Cross-Origin Resource Sharing)
CORS는 웹 페이지가 현재 도메인과 다른 도메인에 있는 자원에 접근할 수 있도록 하는 보안 기능입니다.

2. CORS 동작 원리

웹 브라우저에서 자바스크립트가 교차 출처의 자원에 접근하려 할 때, 서버는 응답에 CORS 관련 HTTP 헤더를 포함하여 브라우저에 접근 권한을 알려줍니다.

  • 요청: 자바스크립트가 서버에 HTTP 요청을 보냅니다.
  • 응답: 서버는 응답과 함께 CORS 헤더를 포함하여 자원 접근을 허가합니다.
  • 브라우저의 역할: 브라우저는 CORS 헤더를 확인하여 자바스크립트의 접근을 허용합니다.

3. CORS 헤더

서버가 응답에 포함할 수 있는 CORS 헤더는 다음과 같습니다:

  • Access-Control-Allow-Origin: 자원에 접근을 허용할 출처를 지정합니다. 예를 들어, ``를 사용하면 모든 출처를 허용합니다. 특정 출처만 허용하려면 해당 출처의 URL을 명시할 수 있습니다.
  • Access-Control-Allow-Methods: 허용된 HTTP 메서드를 명시합니다 (예: GET, POST, PUT, DELETE 등).
  • Access-Control-Allow-Headers: 클라이언트가 요청에 포함할 수 있는 헤더를 명시합니다 (예: Content-Type, Authorization 등).
  • Access-Control-Allow-Credentials: 자격 증명(쿠키, 인증 헤더 등)을 허용할지를 결정합니다.

단순요청

단순 요청은 CORS에서 특별히 안전하다고 간주되는 HTTP 요청의 종류입니다. 브라우저는 이러한 요청을 특별히 처리하여, CORS 헤더가 제대로 설정되어 있는지에 따라 교차 출처 요청을 허용합니다.

단순 요청은 다음과 같은 조건을 만족하는 요청을 말합니다

CORS-safelisted MethodCORS-safelisted request-header
GET
POST
HEAD
(HEAD 메서드는 GET 메서드와 유사하지만, 자원의 본문(Body)을 포함하지 않고 오직 헤더만 반환)
accept
accept-language
content-language
content-type
• 값이 application/x-www-form-urlencoded", " multipart/form-data", "text/plain" 인것

참조 Fetch Standard : CORS-safelisted정리 사이트( http 메소드/ http헤더)

브라우저는 위와같은 단순요청이면서 Access-Control-Allow-Origin 헤더가 설정되어있는 경우
이를 "안전한 요청"으로 간주하여 추가적인 CORS 검사를 수행하지 않고
자바스크립트가 교차 출처의 자원에 접근할수 있게합니다.

하지만 사진 파일 업로드(multipart/form-data)가 아니라면 대체로 REST API가 Content-Type 으로 application/json 을 사용하기 때문에 사실상 단순요청은 지켜지기 어려운 조건입니다.

Preflight Request

Access-Control-Allow-Origin 헤더가 설정되어 있지만 단순 요청이 아닌 경우, 브라우저는 먼저 사전 요청(Preflight Request)를 보냅니다.

이 요청은 OPTIONS 메서드를 사용하여 클라이언트가 보내려는 요청의 메서드와 헤더가 서버에서 허용되는지 확인합니다.

Preflight의 역할

DELETE 메서드를 사용한 요청이 프리플라이트(preflight) 요청을 거치지 않고 바로 서버에 도달하는 경우, 서버는 요청을 처리하고 실제 데이터베이스(DB)에서 데이터를 삭제할 수도 있습니다.

  • 보안 강화: 프리플라이트 요청을 통해 서버는 요청을 검증할 수 있으며, 잠재적으로 악의적인 요청이 서버에 도달하는 것을 방지합니다. 클라이언트가 허용되지 않은 메서드나 헤더를 사용하려 할 때 서버가 이를 사전에 차단할 수 있습니다.

    만약에 크기 큰 Array를 body에 담아서 보내는 요청이 있다고 했을때. 근데 만약 이 요청이 CORS 정책을 위반하는 요청이라면 ? 이 data 를 보낸후, 알고보니 유효하지 않은 요청이라면 불필요하게 리소스를 낭비한 꼴이되고, 서버에도 부하가 클 수 있습니다.

  • 서버 자원 보호: 클라이언트가 보내려는 요청이 유효한지 확인하기 전, 불필요한 서버 작업을 방지할 수 있습니다. 이는 서버의 자원 낭비를 줄이고, 서버에 대한 부담을 줄이는 데 도움을 줍니다.

Preflight는 아래와같은 요청헤더와 응답헤더들로 이루어져있습니다.(일부)

Preflight 요청헤더

origin: 요청 전송하는 출처

access-control-request-method : 전송하는 요청의 http 메서드

access-control-request-headers: 전송하는 요청에 포함된 http해더리스트

Preflight 응답헤더

access-control-allow-origin: 접근을 허가하는 출처

access-control-allow-headers: 요청으로 전송 가능한 HTTP 헤더 리스트

access-control-allow-methods: 요청으로 사용할 수 있는 메서드 리스트

access-control-max-age: Preflight 결과를 캐싱하는 시간

본요청 전에 Preflight request 응답헤더의 allow-methods 에 DELETE 가 없는데 요청을 한다면 Cors를 위반하므로 브라우저는 요청을 전송하지 않게됩니다.

쿠키를 포함하는 요청 전송

https는 상태를 유지할 수 없으므로 로그인 상태 유지를 위해 쿠키에 데이터를 저장해야합니다.

보안 정보가 유출되는 리스크를 줄이기위해 쿠키를 서버로 전송하지 않는 것이 기본값 이기 때문에, 명시가 필요합니다.

fetch(url, {
  credentials: 'include'
})

위와 같이 credentials 옵션을 사용할 수있는데, 설정 가능한 값은 아래와 같습니다.

omit : 쿠키 전송 X (기본값)

same-origin : 동일 출처만 쿠키를 전송

include: 출처에 상관없이 항상 쿠키를 전송

서버또한 res.header("Access-control-Allow-Credentials", true); 로 쿠키를 포함하는 요청을 열어주어야합니다. (안열었을경우 Preflight단계에서 CORS 에러 반환)

CORS 요청 모드

js단계에서도 “mode” 옵션을 사용해 CORS관련 설정을 할 수있습니다.

fetch(url, {
  mode: 'cors'
})

설정 가능한 값은 아래와 같습니다.

same-origin : 교차출처에 요청이 전송되지 않고 에러발생

cors : 기본값

no-cors : 교차출처로 요청은 단순요청만으로 제한

이미지의 CORS

img 와 script 등의 HTML 요소를 사용하는 요청은 기본설정으로 CORS 를 사용하지 않지만, crossorigin 속성을 부여하면 cors모드로 요청을 전송 할 수 있습니다.

crossorigin 속성을 지정하는 값에 따라 쿠키의 전송도 제한 할 수 있는데, 아래와 같습니다.

 <img src="http://site.example:3000/sample.png" alt="sample" crossorigin="" />
 => 동일출처만 전송
 <img ... crossorigin="anonymous" />
 => 쿠키전송X
 <img ... crossorigin="use-credentials" />
 => 모든출처에 쿠키 전송

프로세스 분리에 따른 사이드 채널 공격 대책

하드웨어 사이드채널 공격은 시스템의 물리적 특성을 활용하여 민감한 정보를 추출하는 기법입니다.

그중 책에서는 스펙터에 대해 언급이 있었는데,

스팩터는 CPU의 추측 실행 기능을 사용하여 메모리 부분에 액세스한 다음 타이밍 공격을 가해 해당 메모리에 저장된 값을 유추해냅니다.

완벽히 이해하기엔 제겐 너무 어려워서, 더 깊은 이해를 원하시는분들을 위해 스팩터 데모 사이트 를 공유드립니다.

크롬의 Site Isolation

Site Isolation은 악성 웹 페이지를 사용해 다른 웹 사이트의 데이터를 쉽게 탈취하지 못하도록 만들어진 Protection 입니다. 이는 각 웹 사이트간의 접근을 제한하고, Extension 등 일반 웹 페이지보다 높은 권한을 가진 앱에서도 쉽게 접근할 수 없도록 제한하는 기능을 수행합니다.

Spectre 공격이 발생하더라도 훔칠 만한 데이터가 동일한 프로세스에 존재하는 것을 방지하는 사이트 격리라고 할 수 있습니다.

여기서 말하는 사이트는 출처와는 다른 정의를 갖는 보안경계인데, 출처단위로 프로세스를 분리하면 브라우저의 일부기능이 동작하지 않게 될수 있으므로 출처보다 제한이 느슨한 사이트 단위로 프로세스를 분리합니다.

Site Isolation구조가 생기기 전에는 iframe에 삽입된 다른 사이트의 접근을 막을 방법이 없었지만. 현재는 Site Isolation에 의해 브라우저가 ifame을 통해 다른 사이트의 메모리 데이터에 접근하는것을 막을 수 있게 되었습니다.

출처마다 프로세스를 분리하는 구조

Site Isolation을 통해 대부분의 사이드 채널 공격은 막을 수 있지만, 위와같이 출처보다 제한이 느슨하기 때문에 출처단위의 사이드 채널 공격은 막지 못합니다.

이를 막기위해서 출처마다의 프로세스를 분리하는 구조가 등장했습니다.

출처마다의 프로세스를 분리하는 구조를 Cross-origin Isolataion 이라고하는데, 이 Cross-origin Isolataion은 웹 개발자가 임의로 활성화 할 수 있습니다.(일반적으로 백엔드에서 지정합니다.)

CORP(Cross-Origin-Resource-Policy) : 리소스를 가져올때 동일 출처 또는 동일 사이트로 제한

Cross-Origin-Resource-Policy : same-origin // 동일 출처 제한
Cross-Origin-Resource-Policy :same-site // 동일 사이트 제한
Cross-Origin-Resource-Policy : cross-origin // 모든출처에서 로드

COEP(Cross-Origin-Emdedder-Policy): 외부 리소스를 로드할 때 그 리소스가 CORP 헤더를 통해 안전하게 공유될 수 있는지 확인

Cross-Origin-Emdedder-Policy : require-corp // 기본값 none

COOP(Cross-Origin-Opner-Policy): 어디까지 프로세스공유를 할지 설정

Cross-Origin-Opner-Policy: unsate-none // 기본값,iframe이 동일프로세스에서 실행
Cross-Origin-Opner-Policy: same-origin // 동일출처에서 열리는 페이지와만 프로세스 공유
Cross-Origin-Opner-Policy : same-origin-allow-popups: 동일출처 + 팝업과 프로세스 공유

Cross-Origin-Opner-Policy: same-origin 설정시 결제팝업이 정상적으로 동작하지 않을 수 있습니다.

그런경우엔 same-origin-allow-popups 설정을 할 수 있습니다.

profile
👨🏻‍💻 Front-End Developer

0개의 댓글