It,develop

[CS] AJAX, SOP, CORS ♦︎

Yujzu 2025. 1. 14. 11:42

 

# AJAX (Asynchronous JavaScript and XML)

= 브라우저가 페이지를 새로 로드하지 않고도 서버와 데이터를 주고받을 수 있게 해주는 비동기 웹 기술

[ 특징 ] 

- 비동기 데이터 통신 : 웹 페이지를 다시 로드하지 않고, 필요한 데이터만 서버와 교환한다.

- 브라우저 내장 객체 사용 : 서버와의 통신은 주로 XMLHttpRequest 객체나 Fetch API를 통해 처리한다.

- 형식 유연성 : 응답 데이터는 XML, JSON, HTML, 텍스트, 바이너리 데이터 등 다양한 형식을 사용할 수 있다.

- 검색어 자동완성, 무한 스크롤, 폼 제출, 실시간 채팅 등에 사용

 

[ 예시 코드 ]

// XMLHttpRequest 사용
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1", true);
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log("Response:", JSON.parse(xhr.responseText));
  }
};
xhr.send();

// Fetch API 사용
fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then((response) => response.json())
  .then((data) => console.log("Response:", data))
  .catch((error) => console.error("Error:", error));

 

# Origin (출처)

- URL의 구성 요소 중 3 가지 요소로 정의된다.

= 프로토콜 (http, https) + 도메인 (example.com, api.example.com) + 포트(번호)

ex )

URL : https://www.example.com:443/path 

Origin : https://www.example.com:443

 

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

= 같은 Origin에서만 리소스를 요청하거나 접근할 수 있도록 제한하는 보안 정책

= 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식

- 웹 브라우저의 기본적인 보안 정책은 동일 출처 정책으로 웹 페이지에서 스크립트를 통해 다른 출처의 리소스에 접근할 수 없다.

 

# CORS (Cross-Origin Resource Sharing, 교차 출처 자원 공유)

= SOP 제한을 완화하기 위해 사용되는 표준 메커니즘

- 외부 도메인 서버와 통신하기 위한 방식을 표준화한 스펙

- 서버에서 특정 Origin의 요청을 허용하도록 설정할 수 있다.

- 서버와 클라이언트가(도메인 사이에) 정해진 헤더를 통해 리소스에 접근할 수 있도록 허용 or 차단하는 방식

 

[ CORS 허용 원리 ]
- Simple Request: 요청을 서버로 바로 보냄 → 서버가 응답 헤더로 CORS 정책을 전달 → 정책 위반 시 브라우저가 요청을 차단

- Preflight 요청이 필요한 경우: OPTIONS 요청 → 서버의 CORS 응답 확인 후 → 실제 요청 수행

 

1. Client 요청 => CORS 정책 확인 필요하다 판단 => Preflight 요청

2. 서버는 브라우저가 요청을 보내도 되는지 CORS 헤더로 응답한다.

3. 브라우저는 서버의 응답을 보고, 요청이 허용되었는지 판단한다.

4. Preflight 요청이 성공하면 브라우저는 실제 요청을 실행한다.

 

# Preflight Request (프리플라이트 요청)

= 브라우저가 실제 요청을 보내기 전에 서버가 해당 요청을 허용하는지 확인하는 작업

= HTTP 요청 전에 CORS 정책을 검증하기 위해 브라우저에서 서버로 보내는 추가 요청

- OPTIONS 메서드로 요청을 보낸다

예시)

OPTIONS /api/resource HTTP/1.1
Host: api.example.com
Origin: https://frontend.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization

 

[ Preflight 요청 조건 ]

- 모든 Client 요청에 발생하는 것은 아님

- 'Simple Requests' 가 아닐 때 : application/json 을 사용하거나 Authorization 헤더를 포함하면 Preflight 요청이 필요하다.

- CORS 정책에 민감한 요청일 때 : PUT, DELETE, PATCH 메서드를 사용할 때

 

# HTTP 응답 헤더

- 서버는 요청된 Origin을 확인한 뒤, 이를 허용할지 말지를 결정하고 응답한다.

응답에는 다음과 같은 CORS 관련 헤더가 포함된다

- Access-Control-Allow-Origin : 특정 출처(origin)을 허용하거나 *로 모든 출처를 허용할 수 있다.

- Access-Control-Allow-Methods : 허용되는 HTTP 메서드를 정의한다. (GET, POST, PUT, DELETE)

- Access-Control-Allow-Headers : 클라이언트가 요청할 때 사용할 수 있는 헤더 지정 (Content-Type, Authorization

- Access-Control-Allow-Credentials : 쿠키나 인증 정보를 포함한 요청을 허용하려면 활성화 (true)

예시)

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Authorization

 

# CORS 에 대처하는(우회하는) 방법
외부 서버로 ajax 요청이 안될 경우 => 

 

1. 서버에서 CORS 요청이 허용되도록 구현

- 서버에서 CORS 요청 핸들링하기, 서버로 날아온 preflight 요청을 처리

 

2. CORS 구현이 안되어 있는 서버로 AJAX 요청시 : jsonp 방식으로 요청

- <script> 태그를 사용해 데이터를 요청

- Get 요청만 지원한다.

- 보안 문제가 있고, 예전 방식이다.

 

3. 웹 브라우저 실행 옵션이나 플러그인을 통한 SOP 회피

- 웹브라우저 실행 시 외부 요청을 허용하는 옵션을 사용

- 크롬같은 웹 브라우저들은 실행 시 커맨드 라인 옵션을 통해서 외부 도메인 요청가능 여부를 확인하는 동작을 무시하게 할 수 있다.

- 외부 요청을 가능하게 해주는 플러그인 설치

 

4. 프록시 서버 사용

- 서버와 클라이언트 사이에 프록시를 배치하여 요청을 우회함

- 클라이언트는 프록시 서버를 동일 출처로 인식하기 때문에 CORS 에러를 피할 수 잇다.

// package.json
{
  "proxy": "http://backend-server:3000"
}

 

# jsonp

- 웹 브라우저에서 CSS나 JS 같은 리소스 파일들은 SOP에 영향을 받지 않고 로딩이 가능합니다. 이런 점을 응용해서 외부 서버에서 읽어온 js 파일을 json으로 바꿔주는 일종의 편법적인 방법입니다.

단점은 리소스 파일을 GET 메서드로 읽어오기 때문에 GET 방식의 API만 요청이 가능합니다.