내용 들어가기 전 용어 정의

Domain

domain

최상위 도메인(TLD: Top-Level Domain) : 인터넷 주소를 분류하는 역할을 한다.

ex) .com, .org, .net, .edu, .kr, .jp, .uk 

 

2차 도메인(SLD: Second-Level Domain) : 조직 또는 웹사이트의 고유 이름을 나타낸다.

ex) goole, naver, tistory, youtube

 

서브 도메인 : 주 도메인의 하위 영역을 나타낸다.

 

루트 도메인 : 도메인의 기본 주소로, 보통 SLD + TLD 조합으로 이루어진다.

 

SOP (Same-Origin Policy)

웹 브라우저가 보안을 위해 출처가 같은 리소스에 대해서만 요청을 허용하는 정책이다.

동일 출처는 프로토콜, 도메인, 포트가 모두 동일한 경우를 의미한다.

 

A 페이지: https://example.com

B 리소스: https://api.example.com

위 경우도 동일 출처가 아니다. 서브 도메인이 있어도 다른 출처로 여긴다. 

 

CORS (Cross-Origin Resource Sharing)

동일 출처 정책(Same-Origin Policy)을 우회할 수 있도록 설계된 메커니즘이다.

SOP는 웹 브라우저 정책이고, CORS는 서버 간 통신에서 발생하지 않는다.

 

포워드/리버스 프록시

특성 forward proxy reverse proxy
용도 클라이언트의 요청을 대신 전달 서버의 요청을 대신 처리
주요 목적 익명성 보호, 필터링, 차단 우회 부하 분산, 보안 강화, SSL 종료, 캐싱
대상 클라이언트 (사용자) 서버 (서비스 제공자)

forward는 인트라넷 생각하면 된다.

 

nginx 리버스 프록시로 CORS 해결하기

시스템 구성

도커로 구성한 시스템 예시

Host : 목표 지점 도메인

Origin : 출처 도메인

 

client <=> nginx

nginx에서 정적 파일(html, css...)을 서빙하고 있고, 클라이언트에서 자기 자신(nginx)으로 요청을 보내므로 Host와 Origin을 동일하게 할 수 있다.

 

nginx <=> 서버, nginx reverse proxy 설정

nginx 변수 예시

$http_host = 213.111.23.11:9999 (포트까지 포함한 host)

$host = 213.111.23.11 (포트 제외한 host)


  
## nginx.conf
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
client_max_body_size 30M;
....
# 요청 URL과 origin이 다르면 와일드 카드말고 허용 origin 명시해줘야 정책 안걸림
map $http_origin $origin_allowed {
default 0;
http://localhost:1111 1;
}
map $origin_allowed $allow_origin {
default "*";
1 $http_origin;
}
# http
server {
listen 80;
server_name _;
include common/_http.conf;
}
...
}

 


  
## _http.conf
location /server {
include common/_cors-header.conf;
include common/_cors-options-response.conf;
# Host Origin 일치하거나, Host만 있어도 ok
# Host만 있을 때는 $http_host로 (기본 port면 $http도 무관)
# dns 붙이고 나서는 origin 없으면 안됨, ip로 할 때만 origin 없이 가능
rewrite ^/server_prefix/(.*)$ /$1 break;
proxy_pass http://server:8088;
proxy_set_header Host $http_host;
proxy_set_header Origin $scheme://$http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

 


  
## _cors-header.conf
add_header 'Access-Control-Allow-Origin' $allow_origin always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE, PATCH' always;
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Accept' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Vary' 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers' always;
add_header Cache-Control "no-cache, no-store, max-age=0, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
add_header Connection "keep-alive";
add_header Keep-Alive "timeout=20";
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "DENY";
add_header X-XSS-Protection "0";
add_header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers";
## _cors-options-response.conf
# if 블럭이 전역 블럭보다 먼저 처리됨
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $allow_origin always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE, PATCH' always;
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Accept' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Vary' 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers' always;
add_header 'Content-Length' 0;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Access-Control-Max-Age' 7200;
return 204;
}

 

add_header는 클라이언트가 받을 응답에 대한 부분으로 서버에 전달되는 헤더 설정은 아니다.

 

정적 파일 서빙을 다른 origin에서 하고 리버스 프록시인 nginx로 요청을 보낸다면 다르겠지만,

클라이언트가 자신에게(nginx) 요청을 보낼 때, 위의 모든 add_header가 없어도 cors에 걸리는 건 없다.

 

잘 동작한 proxy_set header 설정 방법들

X-aa-bb 헤더들은 CORS와 무관하다.

 

1. Origin 설정 없이 Host만( 기본 포트 아닐 경우 $http_host )

dns 서버 붙인 상태에서는 Origin 설정 없이 Host만 설정하면 안 됨

ip주소 요청일 때만 Origin 없이 가능했음


  
proxy_set_header Host $http_host;

 

1. Origin과 Host를 일치
    http_host를 사용하던, $host를 사용하던 Origin과 Host에 동일하게 적용하면 된다.


  
proxy_set_header Host $http_host;
proxy_set_header Origin $scheme://http_host;
# ==============================================
proxy_set_header Host $host;
proxy_set_header Origin $scheme://host;
# nginx에 https적용하고 프록시로 사용할 경우 (내부 통신은 http 일 때)
proxy_set_header Host $http_host;
proxy_set_header Origin http://$http_host;

 

1. Host를 설정하고 서버에서 설정한 allowOrigin도 가능하다.


  
proxy_set_header Host $http_host;
proxy_set_header Origin $scheme://abc:5555;
==========================================
proxy_set_header Host $host;
proxy_set_header Origin $scheme://abc:5555;

Origin 헤더를 제외하면 서버 간 통신으로 보고 CORS 메커니즘을 실행하지 않는 것 같고

모든 경우에서, 요청에 Host 헤더를 제외하면 Spring boot 다른 검증에서 400을 뱉는 것 같다.

 

( 이것저것 더 확인하고, 해당 포스팅 nginx.conf 수정/보완 )

 


참고

https://backtony.tistory.com/63

 

NGINX - CORS 처리하기

출처(Origin)이란? 출처(Origin)은 Scheme(protocol), Host, Port로 구성되어 있습니다. http, https의 경우에는 프로토콜이 포트 번호를 포함하고 있기 때문에 생략 가능하지만, 만약 포트를 명시함다면 포트번

backtony.tistory.com

 

 

'DevOps > Nginx' 카테고리의 다른 글

headers-more-nginx-module docker image  (0) 2024.12.21
docker-compose nginx load-balancing (spring, node, ws)  (0) 2023.08.28