본문 바로가기
이론/Backend

Nginx 리버스 프록시로 Mixed Content 우회하기

by 유세지 2023. 3. 12.

 

 

우리가 어떤 웹 서비스를 배포한다고 하면, 흔히 프론트엔드단에 보안 접속을 위한 https 프로토콜 연결을 적용해주게 됩니다. http대신 https를 사용함으로써 통신 내용을 암호화하면 중간자로부터 사용자의 정보를 보호할 수 있기 때문에 대부분의 서비스가 https 연결을 사용하고 있습니다.

 

티스토리 블로그 또한 https 연결을 사용하고 있습니다.

 

이러한 특성 때문에 https 프로토콜을 사용하는 측에서는 오직 https 프로토콜을 사용하는 서비스끼리만 통신할 수 있습니다. 우리가 https 프로토콜을 사용한다고 해도, 상대측이 http 프로토콜을 사용하고 있다면 부분적으로만 암호화가 이루어진 상태이기 때문에 공격자가 암호화되지 않은 정보에 접근할 수 있어 위험하기 때문입니다.

 

실제로 https 프로토콜을 이용하는 측에서 http 프로토콜을 이용하는 측으로 연결을 시도하면, 크롬 브라우저의 경우 혼합 콘텐츠(Mixed Content) 오류를 발생시키며 연결을 거부합니다.

 

혼합 콘텐츠 또한 교차 출처 리소스 공유(CORS)처럼 사용자의 보안을 위해 브라우저에서 걸어준 일종의 안전장치이지만, 막상 개발을 하는 입장에서는 번거로운게 사실입니다. 저도 이번에 개인 프로젝트를 진행하며 혼합 콘텐츠 오류를 맞닥뜨리게 되었는데, 강제로 무시하고 통신을 진행하는 대신 올바른 방법을 통해 해결하려 시도했던 과정을 정리해보겠습니다.

 

 

문제 상황

제 프로젝트의 경우, 프론트엔드와 백엔드를 한 서버에 올려 사용하고 있었습니다. 프론트엔드의 경우 CloudFlare를 통해 https 연결을 사용하도록 세팅되어 있었고, 백엔드는 일반적인 http 통신을 사용하고 있었습니다. 바로 이 부분에서 문제가 발생했습니다.

 

먼저 현재 프로젝트의 구조를 보겠습니다.

 

요청이 들어온 포트에 따라 Front가 응답할지, Back이 응답할지 정해집니다.

 

 

필요한 부분만 살펴보면, 요청이 80포트(http)로 들어오면 프론트단에서 페이지를 응답해주고, 6000포트(미리 세팅해 둔 백엔드 전용 포트)로 들어오면 백엔드 서버에서 받아 응답을 처리해주는 방식입니다. 완성된 페이지를 보고 있는 사용자는 아래 그림처럼 백엔드 측에 api를 요청하게 됩니다.

 

 

 

요청은 전송되지 않습니다.

 

 

그러나 이 api 요청은 전송되지 않습니다. 사용자가 보고있는 완성된 페이지는 CloudFlare로부터 인증서를 받아 https 프로토콜을 사용하고 있는 상태인데, 여기에서 http로 통신을 받는 백엔드 측에 연결을 시도했기 때문입니다. 위에서 이야기했던 혼합 콘텐츠 오류가 발생하고 있는 상태입니다.

 

문제를 해결하려면 오류의 원인을 없애야합니다. 원인만 보면 https 프로토콜에서 http 프로토콜로 연결을 시도하기 때문에 발생하는 문제이니, 같은 https 프로토콜로 연결을 지정하면 됩니다. 이를 위해선 몇 가지 사전 준비가 필요합니다.

 

 

해결 과정

먼저 프론트에서 Base URL을 변경해줍니다. 기존의 http을 사용한 주소대신 https 주소로 바꿔주었습니다.

 

// 변경 전 .env
BASE_URL=http://example.com:6000

// 변경 후 .env
BASE_URL=https://example.com/api

 

기존의 포트번호 대신, api 요청을 위한 주소임을 구분하려고 주소 뒤에 "/api" 를 추가해주었습니다. 이제 nginx 설정 파일을 다시 확인하겠습니다.

 

# example.conf

server {
    listen 80;
    server_name example.com;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # 리버스 프록시로 /api로 들어오는 요청을 백엔드로 매핑해줍니다.
    location /api {
        proxy_pass http://localhost:6000;
    }

    location / {
        proxy_pass http://localhost:3000;
    }
}

 

별다른 설정없이 열려있던 백엔드 서버 포트(6000)를 그대로 사용하는 대신, 해당 주소(example.com)의 80포트로 들어오는 요청 중, /api 를 통해 들어오는 요청일 경우 백엔드 서버 포트로 연결해주었습니다. 이렇게 되면 "https://example.com/api" 로 들어오는 요청들이 자동으로 백엔드 서버를 향하게 됩니다. 

 

이제 마지막으로 백엔드 서버를 수정할 차례입니다. 제 경우엔 nest.js를 이용해 서버를 구성하였는데, 컨트롤러 앞쪽에 api를 추가하여 /api 로 들어오는 요청을 받을 수 있도록 변경했습니다.

 

 

앞쪽에 api를 추가했습니다.

 

 

컨트롤러에서 직접 api를 추가하는게 별로 좋은 모양처럼 보이지는 않지만, 이 부분은 추후에 수정하도록 하고 서버에 배포한뒤 테스트해보면 더 이상 혼합 콘텐츠 오류가 발생하지 않는 것을 확인할 수 있습니다.

 

 

마치며

오늘은 Nginx의 리버스 프록시를 이용해 혼합 콘텐츠 오류를 해결해보았습니다. 다소 단순한 방법을 사용해 문제를 해결하긴 했지만, 더 깔끔하고 명쾌한 방법이 있을것 같다는 생각이 막연하게 들었습니다. 다만 아직 찾지 못하고 있네요.

 

해당 서버가 혼자 사용하는 서버가 아닌 몇 사람이 공용으로 사용중인 서버라서 더 상위의 설정은 건드릴 수 없다는 제한이 있다는 것을 고려해보면, 그렇게 나쁜 방법은 아닌 것 같아 글로 정리해보았습니다. 혹시 더 좋은 방법을 찾게 된다면 다시 한 번 정리해서 올려보겠습니다.

 

부족한 글 읽어주셔서 감사합니다.

 

 

반응형

'이론 > Backend' 카테고리의 다른 글

Nest.js에서 로컬 DB 연결하기  (2) 2023.02.05

댓글