리버스 프록시를 도입하게된 계기 💭
졸업작품인 코리(Co:RE)의 서버를 개발하면서 실제로 배포를 위한 환경을 만들려고 하다보니,
보안적인 요소를 생각하지 않을 수 없었다.
1차적으로 생각이 난 부분은 당시 학습하고 있었던 프록시 서버였다.
프록시 서버에 대해 모르는 사람은 해당 포스팅을 참고해주세요!
리버스 프록시 서버를 적용하면 보안상 이점과 여러 장점들을 얻을 수 있는데,
그 중 내가 생각한 장점은 아래와 같았다.
⚙️ 보안
개발자 도구에 WAS의 주소가 그대로 노출되어 다양한 공격의 가능성이 발생한다.
여기에 리버스 프록시를 적용하게 되면 서버를 직접 노출시키지 않고 클라이언트와의 통신을 중계하므로 서버의 실제 위치를 숨기고 보안을 강화할 수 있다.
프록시 서버로 인해 본래 서버의 IP 주소를 노출시키지 않을 수 있어, 해커들의 DDos 공격과 같은 공격을 막는데 용이하다.
⚙️ 로드 밸런싱
리버스 프록시는 여러 서버로 요청을 분산할 수 있으며, 부하 분산을 구현할 수 있다.
추후 서버를 Scale Out 했을 때 Load Balancing 기능까지 수행할 수 있다.
이는 트래픽이 여러 서버에 고르게 분산되어 서버의 성능을 향상시키고 가용성을 높이는 데 도움이 된다.
작업 환경 💻
• AWS EC2 't2.micro'
• 'ubuntu 22.04' AMI
• `Nginx 1.18.0`
생략 과정 ✂️
• AWS 계정 생성
• EC2 생성 (Ubuntu 22.04 AMI 사용)
• 보안규칙 설정
• HTTP 80번 포트에 대해 IPv4, IPv6 허용
• HTTPS 443번 포트에 대해 IPv4, IPv6 허용
• SSH 22번 포트 IPv4 허용
• 볼륨 크기는 EC2 프리티어에서 사용할 수 있는 최댓값인 27GiB 설정
• 스프링부트 서버가 죽지 않도록 `Swap Memory` 설정하여 `t2.micro` 환경에서 3GB의 메모리 흭득
Nginx Reverse Proxy 설정 방법 ⚙️
💻 Shell 명령
# apt-get 업데이트
sudo apt-get update
# Nginx 설치
sudo apt-get install nginx
sudo service start nginx
# nginx Config 파일 열기
sudo vi /etc/nginx/site-available/default
# http 설정 바로 아래에 server 설정을 추가하여 리버스 프록시 설정(사용하지 않는 주석 전부 제거)
💻 /etc/nginx/site-available/default 설정
http {
server {
listen 80; # 포트를 필요에 따라 조정하세요.
#server_name your_domain.com; # 도메인 이름 대신 IP 주소를 사용할 경우 필요 없습니다.
location / {
proxy_pass http://서버_주소:포트; # 백엔드 서버의 IP 주소
proxy_http_version 1.1;
proxy_set_header Connection ""; #504 Bad GateWay 문제 방지
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}
⚙️ proxy_set_header Host $host;
이 헤더는 원격 서버로 전달되는 HTTP 요청 헤더 중 하나이다.
`$host` 변수는 클라이언트가 요청한 호스트 헤더 값을 가지고 있다.
호스트 이름은 일반적으로 `도메인 이름`이나 `IP 주소`인데,
이를 통해 리버스 프록시는 요청을 받은 원격 서버에게 어디로부터 온 요청인지 알려준다.
⚙️ proxy_set_header X-Real-IP $remote_addr;
이 헤더는 `클라이언트의 실제 IP 주소`를 리버스 프록시를 통해 전달한다.
이것은 원격 서버가 클라이언트의 실제 IP를 알고자 할 때 사용된다.
⚙️ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
일반적으로 HTTP 요청에는 `X-Forwarded-For` 헤더가 포함되어 있다.
이 헤더는 `클라이언트`가 `어떤 IP 주소를 통해 요청을 보냈는지`를 기록하며, 여러 프록시 서버를 거친 경우 쉼표로 구분된 목록으로 기록된다.
Nginx에서 `$proxy_add_x_forwarded_for` 변수는 이 `X-Forwarded-For` 헤더의 값을 가져와 저장한다.
이를 통해 서버는 실제 클라이언트의 IP 주소를 파악할 수 있다.
예를 들어, 클라이언트 A에서 요청이 오고, 그 요청이 Nginx 프록시 서버 를 거쳐 백엔드 서버로 전달되면,
X-Forwarded-For 헤더에는 "A, Nginx_IP" 와 같이 표시된다.
이때 $proxy_add_x_forwarded_for 변수에는 "A, Nginx_IP"와 같은 값이 저장된다.
연결 완료 ✅
`Nginx` EC2의 IP에 `80번 포트`로 접속했는데 `SpringBoot` EC2의 IP에 `8080번 포트`로 접속한 것과 동일한 화면이 출력되는 것을 확인할 수 있다.
또한 `SpringBoot`의 포트인 `8080`번으로 접속하면, 접속할 수 없는 것을 알 수 있다.
이는 우리가 `AWS의 EC2 보안 그룹의 인바운드 규칙`에서 `8080번` 포트를 외부에서 접속하지 가능하도록 설정해주지 않았기 때문이다.
위와 같은 설정들을 통해 무조건 `리버스 프록시`를 거쳐서 접속할 수 있게 된 것이다.
추후 프로젝트 개선 방향 🤔
- `WAS`에 대한 접근과 정보 노출을 방어했지만 아직 `Nginx`를 통해서 요청하면 `WAS`에 요청하는 것과 똑같이 요청하여 데이터를 흭득할 수 있다. 그렇기에 고의적으로 `리버스 프록시 서버`에 많은 요청을 보내게 되면, 그대로 받아들여 서버에 과부하가 오게 된다.
- 또한 지금 개발하고 있는 서비스 `Co:RE`는 유저들이 운영 측의 `GPT API Key`를 사용하여 무료로 응답값을 얻는 형식이다. 때문에 더더욱 많은 고의적인 요청이 보내지면 금전적으로 큰 손해를 볼 수 밖에 없다
- 이에 대한 결론으로 다음 개발 과제는 `과도한 트래픽에 대한 방어`로 잡았다.
- `Bucket4j` 라이브러리를 사용하면 Token-Bucket 알고리즘을 통해
유저들에게 API를 요청할 수 있는 `Token`을 주고 Token의 `사용 시간` 또는 `사용 횟수`에 제한을 걸어,
고의적인 요청을 방어할 수 있다고 한다.
때문에 이를 공부하여 적용해보고자 한다.
'BackEnd' 카테고리의 다른 글
GPT API의 응답 값을 원하는 형태로 만들어보자 (with. Chat Completion API & Fine-Tuning) (0) | 2024.06.21 |
---|---|
[인증/인가] JWT란? (with. AccessToken, RefreshToken 사용법) (0) | 2024.06.19 |
프록시(Proxy) 서버란? (0) | 2024.05.19 |
테스트를 위한 객체, 테스트 더블(Test Double) (0) | 2024.04.04 |
[인증/인가] RefreshToken은 왜 Redis를 사용해 관리할까? (with. RTR 방식) (5) | 2023.06.13 |