최근에 경험한 인터뷰 당시 받았던 질문 중 하나인 Proxy Server에 대해
포스팅을 하던 중, CORS까지 묶어서 정리하는 것이 좋겠다는 생각이 들었습니다.
기존에 CORS에 대한 개념과 처리 방법에 대해서만 알고 있었지,
정작 왜 CORS를 처리하기 위한 방법으로
Proxy Server를 사용하는지에 대한 이유를 모르고 있었습니다.
특히, CORS 상황을 제외한 프록시 서버를 사용하는 이유에 대해서는
한 번도 생각해보지 않았는데 이번 기회를 통해 파악할 수 있게 되었는데요.
먼저 CORS의 동작과 CORS 문제 해결 방법에 대해 정리 후
Proxy Server에 대한 이야기를 해볼까 합니다.
1️⃣ CORS의 동작 원리
출처 정의 - 브라우저 요청 처리 - Preflight 요청 - 서버 응답 - 브라우저 요청 처리의 5단계로 이뤄집니다.
1. 출처 정의
출처는 프로토콜(HTTP/HTTPS), 도메인, 포트 번호로 구성되어 있습니다.
ex) http://jiwon.com:80 or https://jiwon.com:443은 서로 다른 출처로 여겨지겠죠?
2. 브라우저 요청 처리
브라우저가 다른 출처의 API 서버에 요청을 보낼 때, CORS 정책을 확인하는데요.
요청이 다른 출처일 경우, 브라우저는 CORS 헤더를 포함하여 요청을 보냅니다.
3. Preflight 요청
preflight 요청 시점
- GET, HEAD, POST 외의 다른 HTTP 메서드 사용
- 기본적인 헤더 외의 커스텀 헤더 사용
- application/json 등 특별한 Content-Type 사용
위의 경우에 해당된다면 먼저 OPTIONS 메서드를 사용해 사전 요청(preflight request)을 보냅니다.
preflight request를 통해 서버가 원래의 요청을 허용할지를 확인합니다.
4. 서버의 응답
서버는 CORS 헤더를 포함한 응답을 반환하는데요.
주요 헤더에는 HTTP 통신 시 자주 접했던 Access-Control-Allow-Origin,
Access-Control-Allow-Methods, Access-Control-Allow-Headers,
Access-Control-Allow-Credentials가 포함됩니다.
이 헤더들은 요청을 허용할 출처와 메서드, 헤더를 정의합니다.
5. 브라우저의 요청 처리
서버가 CORS 정책에 따라 응답하면, 브라우저는 이를 확인하고 요청을 진행합니다.
반면, 허용되지 않는 출처일 경우 브라우저는 요청을 차단하고 오류를 발생시킵니다.
2️⃣ 프론트엔드에서의 CORS 문제 해결 방법
credential 또는 withCredential 설정
Fetch API, Ky를 사용할 때)
credentials: 'include'로 설정하여 인증 정보를 포함합니다.
//fetch case
fetch('http://api.example.com/data', {
method: 'GET',
credentials: 'include'
}).then(response => response.json());
// ky case
import ky from 'ky';
ky.get('http://api.example.com/data', {
credentials: 'include'
}).then(response => response.json())
axios를 사용할 때)
withCredentials: 'true'로 설정하여 인증 정보를 포함합니다.
import axios from 'axios';
axios.get('http://api.example.com/data', {
withCredentials: true
})
.then(response => {
console.log(response.data);
})
Proxy Server 설정
React에서의 Proxy Server와 Next.js에서의 Proxy Server 설정 방법은 다릅니다.
적용 방법은 구글링을 통해 금방 찾을 수 있으니 차이점만 간단히 짚어봤습니다.
왜 서로 다른 Proxy Server 설정이 필요할까?
결론: 각 프레임워크의 특성이 다르기 때문입니다.
React의 경우에는 CRA를 통한 간접적인 Webpack Dev Server 사용으로
기본 설정이 이미 완료되어 있어 package.json에 설정한 proxy가
Webpack Dev Server로 직접 전달되는데요.
Next.js의 경우, 자체적으로 프록시 설정을 지원하는 방법이 없기 때문에
Custom Dev Server를 설정하여 프록시를 구현해야한다는 특징이 있습니다.
docker를 통한 설정
(솔직히 docker는 제가 잘 알지 못하기 때문에
docker가 익숙해지면 내용을 추가하겠습니다.)
3️⃣ 그런데 Proxy.. 가 뭘까?
CORS 문제를 해결할 수 있는 방법으로 Proxy를 설정도 해준다는 것은 알고 있죠.
하지만 정작 프록시 서버가 무엇인지, 설명하라고 하면 저는 말하지 못했습니다.
그래서 정리해 봤습니다.
클라이언트와 서버 사이에서 중개 역할을 하는 서버
클라이언트의 요청을 받아서 실제 서버에 전달하고(= forward proxy)
서버의 응답을 다시 클라이언트에 전달합니다(= reverse proxy).
이를 통해 클라이언트는 직접 서버에 접근하지 않고도 원하는 데이터를 받을 수 있습니다.
4️⃣ 왜 Proxy Server를 사용하면 CORS에 대처할 수 있을까?
서버 측 요청과 응답을 대신 받아주기 때문입니다.
프록시 서버는 클라이언트의 요청을 받아서 서버 측에서 다른 도메인으로 요청을 보내기 때문에
브라우저의 보안 제한을 받지 않습니다.
CORS 정책을 적용받지 않기 때문에 자유롭게 요청을 할 수 있게 됩니다.
프록시 서버는 API 서버로부터 받은 응답을 클라이언트로 다시 전달합니다.
이때 프록시 서버가 응답 헤더에 CORS 관련 정보를 수정하거나 추가할 수 있어
클라이언트가 정상적으로 응답을 수신할 수 있도록 도와줍니다.
5️⃣ CORS를 제외한, Proxy Server를 사용하는 이유
여러 이유가 존재했지만 제일 익숙했던 것들을 꼽아보자면 아래와 같습니다.
1. 직접적인 서버 접근을 차단하여 DDoS 공격이나 해킹 시도 예방 가능.
2. 캐싱을 통해 서버의 부하를 줄이고, 클라이언트의 응답 속도 개선.
3. 특정 웹사이트나 콘텐츠 접근 제한을 통해 불필요한 웹사이트 접근 차단에 유용.
반면 익숙하지 않았던 이유도 존재하는데요.
로드 밸런싱과 모니터링&로깅, SSL/TLS였습니다.
프록시 서버가 요청을 여러 백엔드 서버로 분산처리해 서버 부하를 관리하는 점이나
요청 및 응답에 대한 모니터링이 가능하단 것,
SSL/TLS 암호화라는 저에겐 다소 생소한 기능도 처리해 준다는 것을 알게 되었습니다.
(SSL/TLS는 인터뷰에도 질문받았던 내용이었는데 당시에 아예 답하지 못했던 기억이.. 나네요)
Reference
기타 구글링
'Network' 카테고리의 다른 글
Preflight Request (0) | 2024.12.11 |
---|