HTTP 헤더 (프록시)

문린이·2023년 3월 28일
0

k8s 환경에서 express-session을 사용할 때 https를 사용하고 있음에도 불구하고 secure 옵션을 true로 설정하면 쿠키가 안 심기는 현상을 해결한 회고록입니다.

cookie-parser vs express-session

Express.js 애플리케이션에서 쿠키를 쉽게 구문 분석하고 생성하기 위한 미들웨어이다.
쿠키는 클라이언트 측에서 로컬 저장소에 저장되는 작은 데이터 조각이며, 웹 애플리케이션에서 세션 관리, 사용자 트래킹 등 다양한 용도로 사용된다.

cookie-parser는 HTTP 요청 헤더의 쿠키 필드에서 쿠키를 구문 분석하고, req.cookies 객체를 통해 액세스할 수 있도록 요청 객체(req)에 쿠키를 추가한다. 또한 res.cookie() 메서드를 통해 HTTP 응답 헤더에 쿠키를 설정할 수 있다.
ex. (logged, access_token = null)

  • 쿠키 구문 분석
  • 쿠키 생성 및 수정
  • 쿠키 유효기간 설정
  • 서명된 쿠키 생성 및 구문 분석

cookie-parser는 secure 옵션이 true 일 때 https가 아닌 http여도 쿠키는 전송된다.

express-session

Express.js 애플리케이션에서 사용자의 세션 관리를 담당하는 미들웨어이다.
세션을 이용하면 클라이언트와 서버 간의 연결 없이도 상태 정보를 유지하고, 이전 요청에서 전달된 데이터를 다음 요청에 사용할 수 있다.

express-session을 사용하면 세션 관리를 위해 일련의 미들웨어 함수를 제공하며, 각 요청에 대해 고유한 세션 ID를 생성하여 세션 데이터를 저장하고 관리한다. 이를 통해 애플리케이션에서는 세션 ID만을 쿠키로 전송하면 되므로, 실제 데이터는 서버에 안전하게 저장된다.
ex. (access_token = ${세션 ID})

express-session의 주요 기능

  • 세션 데이터 저장소 (Redis)
  • 세션 ID 생성
  • 세션 초기화
  • 세션 데이터 저장
  • 세션 데이터 조회
  • 세션 데이터 삭제

express-session의 proxy 옵션

app.use(session({
  secret: 'my-secret-key',
  proxy: true,
  cookie: {
  //
  }
}));

express-session의 proxy 옵션은 애플리케이션이 리버스 프록시 뒤에서 실행될 때 사용된다.

애플리케이션이 리버스 프록시 뒤에 있을 때 프록시 서버는 클라이언트의 요청을 가로채 애플리케이션으로 전달한다. 이 시나리오에서는 클라이언트의 IP 주소가 애플리케이션에 전달되지 않는다.
대신 프록시 서버의 IP 주소가 애플리케이션에 전달됩니다. 예를 들어 보안상의 이유로 애플리케이션이 클라이언트의 IP 주소에 액세스해야 하는 경우 이로 인해 문제가 발생할 수 있다.

이 문제를 해결하기 위해 express-session은 proxy 옵션을 제공한다. 이 옵션이 true로 설정되면 express-session은 클라이언트의 IP 주소를 얻기 위해 프록시 서버가 보낸 X-Forwarded-For 헤더를 신뢰한다.

express-session의 cookie객체의 proxy 옵션

app.use(session({
  secret: 'my-secret-key',
  cookie: {
    secure: true,
    proxy: true, // 자동으로 true로 설정된다.
  }
}));

'cookie' 개체의 'proxy' 옵션은 보안 쿠키를 수신할 때 역방향 프록시를 신뢰할지 여부를 결정하는 데 사용된다. 'true'로 설정하면 'X-Forwarded-Proto' 헤더가 요청의 프로토콜을 결정하는 데 사용되며, 이는 '안전하지 않은 쿠키' 경고를 피하기 위해 리버스 프록시를 사용할 때 필요하다.

프록시 옵션이 참으로 설정되면 요청이 HTTP를 통하지 않고 HTTPS를 통할 때 보안 쿠키가 사용됩니다. 역방향 프록시를 사용할 때 클라이언트와 역방향 프록시 간의 연결은 HTTPS를 통해 이루어지지만 역방향 프록시와 서버 간의 연결은 HTTP를 통해 연결될 수 있기 때문이다. 따라서 쿠키가 안전하지 않게 전송되지 않도록 'proxy' 옵션을 사용하는 것이 중요하다.

HTTPS를 처리하는 리버스 프록시 뒤에 있는 경우에만 proxy 옵션을 true로 설정해야 하며 다른 경우에는 설정하지 않는 것이 중요하다.

(secure 옵션이 true로 설정되면 proxy 옵션은 명시적으로 설정되었는지 여부에 관계없이 자동으로 true로 설정된다.)

proxy

프록시 서버는 클라이언트가 자신을 통해서 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해 주는 컴퓨터 시스템이나 응용 프로그램을 가리킨다.
서버와 클라이언트 사이에 중계기로서 대리로 통신을 수행하는 것을 가리켜 '프록시', 그 중계 기능을 하는 것을 프록시 서버라고 부른다.

정방향 프록시 vs 역방향 프록시

정방향 프록시는 네트워크 외부의 리소스에 액세스하는 데 사용되는 반면 역방향 프록시는 인터넷에서 웹 서버에 대한 액세스를 제공하는 데 사용된다.

정방향 프록시

정방향 프록시는 클라이언트와 인터넷 사이에 있는 서버로, 클라이언트에서 인터넷으로의 요청에 대한 게이트웨이 역할을 한다. 클라이언트가 인터넷에 요청을 보낼 때 요청은 먼저 정방향 프록시 서버로 전송된 다음 클라이언트를 대신하여 요청을 인터넷으로 전달한다.

이는 클라이언트가 방화벽 뒤에 있거나 제한된 네트워크 환경에 있고 네트워크 외부의 리소스에 액세스해야 하는 시나리오에서 유용하다. 정방향 프록시는 네트워크 제한을 우회하고 인터넷의 리소스에 액세스하는 데 사용할 수 있다.

사용 예시

  • 필터링: 정방향 프록시를 사용하여 원치 않는 콘텐츠나 악성 트래픽이 네트워크에 도달하기 전에 필터링할 수 있다.
  • 캐싱: 정방향 프록시는 자주 액세스하는 콘텐츠를 캐시하여 인터넷에서 콘텐츠를 다운로드하는 데 필요한 시간과 대역폭을 줄일 수 있다.
  • 익명성: 정방향 프록시는 클라이언트의 IP 주소를 프록시 서버의 IP 주소로 대체하여 클라이언트의 ID를 마스킹하는 데 사용할 수 있다.
  • 액세스 제어: 정방향 프록시를 사용하여 사용자 ID 또는 기타 기준에 따라 특정 웹사이트 또는 콘텐츠에 대한 액세스를 제한할 수 있다.
  • 대역폭 절약: 정방향 프록시는 콘텐츠를 압축하거나 원치 않는 트래픽을 필터링하여 인터넷 액세스에 필요한 대역폭의 양을 줄일 수 있다.

역방향 프록시

역방향 프록시는 인터넷과 웹 서버 사이에 있는 서버로 인터넷에서 웹 서버로의 요청에 대한 게이트웨이 역할을 한다. 클라이언트가 웹 서버에 요청을 보낼 때 요청은 먼저 역방향 프록시 서버로 전송된 다음 클라이언트를 대신하여 요청을 웹 서버로 전달한다.

이는 웹 서버가 방화벽 뒤에 있거나 제한된 네트워크 환경에 있고 인터넷에서 액세스해야 하는 시나리오에서 유용하다. 역방향 프록시는 들어오는 요청을 여러 웹 서버에 분산하여 부하 분산 및 내결함성을 제공하는 데 사용할 수 있다.

사용 예시

  • 로드 밸런싱: 역방향 프록시는 들어오는 요청을 여러 백엔드 서버로 분산하여 서버 전체에 로드를 분산시키고 전반적인 성능을 향상시킬 수 있다.
  • SSL 종료: 역방향 프록시는 들어오는 요청에 대해 SSL/TLS 암호화를 종료하여 백엔드 서버가 암호화되지 않은 트래픽을 처리하고 서버의 계산 부하를 줄일 수 있다.
  • 콘텐츠 캐싱: 역방향 프록시는 자주 액세스하는 콘텐츠를 캐싱하여 백엔드 서버로 전달해야 하는 요청 수를 줄이고 클라이언트의 응답 시간을 개선할 수 있다.
  • 보안: 역방향 프록시는 들어오는 요청을 필터링하고 악의적인 트래픽을 차단하며 외부 클라이언트의 서버 세부 정보를 마스킹하여 추가 보안 계층을 제공할 수 있다.

HTTP 헤더에서의 프록시

X-Forwarded-For

X-Forwarded-For (XFF) 헤더는 HTTP 프록시나 로드 밸런서를 통해 웹 서버에 접속하는 클라이언트의 원 IP 주소를 식별하는 사실상의 표준 헤더다.
클라이언트와 서버 중간에서 트래픽이 프록시나 로드 밸런서를 거치면, 서버 접근 로그에는 프록시나 로드 밸런서의 IP 주소만을 담고 있다. 클라이언트의 원 IP 주소를 보기위해 X-Forwarded-For 요청 헤더가 사용된다.

X-Forwarded-For: <client>, <proxy1>, <proxy2>

X-Forwarded-For: 203.0.113.195, 70.41.3.18, 150.172.238.178

<client>
클라이언트 IP 주소

<proxy1>, <proxy2>
하나의 요청이 여러 프록시들을 거치면, 각 프록시의 IP 주소들이 차례로 열거된다. 즉, 가장 오른쪽 IP 주소는 가장 마지막에 거친 프록시의 IP 주소이고, 가장 왼쪽의 IP 주소는 최초 클라이언트의 IP 주소다.

X-Forwarded-Host

X-Forwarded-Host (XFH) 헤더는 HTTP 요청 헤더에서 클라이언트가 요청한 원래 Host 헤더를 식별하는 사실상의 표준 헤더이다.
리버스 프록시(로드발란서, CDN) 에서 Host 이름과 포트는 요청을 처리 하는 Origin 서버와 다를 수 있다. 이러한 경우 X-Forwarded-Host 헤더는 원래 사용된 Host 를 확인 하는데 유용하다.
이 헤더는 디버깅, 통계 및 위치 종속 컨텐츠 생성에 사용되며 설계 상 클라이언트의 IP 주소와 같은 개인 정보에 민감한 정보를 노출한다. 따라서 이 헤더가 사용될 때 사용자의 개인 정보를 염두에 두어야한다.

X-Forwarded-Host: <host>

X-Forwarded-Host: id42.example-cdn.com

<host>
전달된 서버의 도메인 이름

X-Forwarded-Proto

X-Forwarded-Proto (XFP) 헤더는 클라이언트가 당신의 프록시 또는 로드 밸런서에 접속하는데에 사용했던 프로토콜(HTTP 또는 HTTPS)이 무엇인지 확인하는 사실상의 표준 헤더이다.
당신의 서버 접근 로그들은 서버와 로드 밸런서 사이에서 사용된 프로토콜을 포함하고 있다. 그러나 클라이언트와 로드밸런서에 사용한 프로토콜은 포함되어 있지 않다.
클라이언트와 로드밸런서 간의 사용된 프로토콜을 확인하기 위해서, X-Forwarded-Proto 요청 헤더가 사용되어 질 수 있다.

X-Forwarded-Proto: <protocol>

X-Forwarded-Proto: https

<protocol>
넘겨져야 할 프로토콜 (http 또는 https)

에러 발생 이유

백엔드 코드 (Express.js)

app.enable('trust proxy');

이 코드는 역방향 프록시 서버에서 설정할 수 있는 X-Forwarded-* 헤더에서 신뢰를 활성화하는 Express.js 애플리케이션 설정이다.

Express 애플리케이션이 리버스 프록시 뒤에서 실행 중인 경우 클라이언트의 요청은 애플리케이션에 도달하기 전에 여러 서버를 통과할 수 있으며 원래 요청 헤더가 수정되거나 손실될 수 있다.

trust proxy 설정은 Express가 리버스 프록시 서버에 의해 설정된 특정 헤더를 찾고 이를 사용하여 클라이언트의 IP 주소, 프로토콜 및 호스트를 올바르게 식별하도록 지시한다.

만약 이 코드가 없다면 위에 그림처럼 req.ip에 올바른 IP 주소가 포함되지 않을 수 있다.
위 그림에 req.ip는 요청이 프록시 또는 로드 밸런서를 통해 전달되었음을 나타내는 주소이다.

테스트

const protocol = req.headers['x-forwarded-proto'];

console.log('X-Forwarded-Proto:', protocol);

결과

즉, 클라이언트에서 사용하는 원래 프로토콜이 https여도 역방향 프록시가 http를 사용하도록 구성되어 있어 에러가 나왔던 것

인프라 코드 (Istio YAML)

use_remote_address: true

이 코드를 통해 Envoy는 Istio 인그레스 게이트웨이의 IP 주소가 아닌 X-Forwarded-For 헤더에 포함된 클라이언트의 IP 주소를 요청의 소스 IP 주소로 사용할 수 있다.

use_remote_address: true 를 설정하면 원래 클라이언트 IP 주소를 보존하는 데 도움이 되며 Envoy가 클라이언트에서 사용하는 원래 프로토콜을 기반으로 올바른 X-Forwarded-Proto 헤더를 설정할 수 있다.

원래는 유효한 인증서로 HTTPS를 사용하고 있으므로 X-Forwarded-Proto 헤더도 https로 설정되었어야 한다. 그러나 HTTP를 통해 Istio 인그레스 게이트웨이에서 요청을 처음 수신한 경우 원래 X-Forwarded-Proto 헤더가 http로 덮어씌었질 수 있다. use_remote_address를 true 로 설정하여 원래 클라이언트 IP 주소가 X-Forwarded-For 헤더에 보존되고 Envoy는 다음을 전달할 때 X-Forwarded-Proto 헤더를 https로 올바르게 설정할 수 있다.

Istio 인그레스 게이트웨이

메시로 들어오는 트래픽의 진입점 역할을 하는 Istio 서비스 메시의 Envoy 기반 구성 요소이다.
인증, 권한 부여, 속도 제한 및 트래픽 셰이핑과 같은 정책을 시행할 뿐만 아니라 트래픽의 대상을 기반으로 메시 내의 적절한 서비스 인스턴스로 트래픽을 라우팅하는 역할을 한다.
Istio 인그레스 게이트웨이는 HTTP, HTTPS, gRPC 및 TCP를 비롯한 다양한 프로토콜을 지원하도록 구성할 수 있으며 OAuth2, JWT 및 LDAP와 같은 다양한 외부 인증 공급자와 통합할 수 있다.
또한 트래픽 미러링, 결함 주입 및 회로 차단과 같은 다양한 트래픽 관리 기능을 지원한다.
전반적으로 Istio 인그레스 게이트웨이는 Kubernetes 클러스터에 대한 인그레스 트래픽을 관리하기 위한 강력하고 유연한 메커니즘을 제공하여 마이크로서비스 기반 애플리케이션을 위한 고급 트래픽 관리 및 보안 기능을 지원한다.

Istio 인그레스 게이트웨이는 Istio 서비스 메시로 들어오는 트래픽의 프록시 역할을 할 수 있다. 들어오는 요청을 처리하고 메시 내의 적절한 서비스로 전달하는 역할을 한다.

use_remote_address: true 를 설정한 후 결과

X-Forwarded-Proto가 정상적으로 https로 나오는 거를 확인할 수 있고 쿠키도 제대로 심겼다.

profile
Software Developer

0개의 댓글