[SKUPLATE] HTTP↔HTTPS, Mixed Content 에러와 CORS 정책 (2)

김태환·2024년 12월 7일
post-thumbnail

이전 글에서 HTTP와 HTTPS에 대해서 먼저 공부했다. 그래야 Mixed Content 에러를 이해할 수 있다고 생각했기 때문이다.
이번 글에서는 Mixed Content 에러가 무엇이고 왜 발생하는지 다뤄보겠다.

Mixed Content 에러, ㅁㅁㅁ무ㅁ머뭐야 이거..?

Mixed Content 에러는 웹 페이지가 HTTPS로 로드되었는데, 해당 페이지에서 HTTP로 된 리소스를 요청할 때 브라우저가 발생시키는 보안 에러이다.
브라우저는 HTTPS 환경에서 모든 요청이 안전해야 한다고 가정하기 때문에, 암호화되지 않는 HTTP 리소스를 로드하면 보안 위협(데이터 탈취, 변조 가능성)이 있다고 판단하여 요청을 차단하거나 경고를 표시한다.

Mixed Content란?

"혼합된 콘텐츠"라는 의미, HTTPS와 HTTP가 혼합된 상태
→ 혼합 상태의 콘텐츠는 보안성이 떨어지고, HTTPS의 장점을 무효화시킨다

Mixed Content의 종류

  • Active Mixed Content (그~냥 차단해버려)
    HTML, JS, CSS, AJAX 요청 등 페이지 동작에 직접적으로 영향을 미치는 콘텐츠
    → JS, API 요청 등이 변조되어 웹 페이지 전체가 공격에 노출된다

    • 보안 위협이 크기 때문에, 브라우저에서 강제로 요청을 차단한다
    • ex) HTTPS 페이지가 HTTP를 통해 JS 파일을 로드할 경우
  • Passive Mixed Content (삐빅- 경고)
    이미지, 비디오, 오디오 등 페이지 표시에는 영향을 주지만 동작에는 영향을 미치지 않는 콘텐츠

    • 보안 위협이 비교적 낮아, 브라우저가 경고만 표시하고 요청을 허용하기도 한다
    • ex) HTTPS 페이지가 HTTP로 이미지를 로드할 경우

Mixed Content 에러, 그럼 왜 발생하는데?

HTTPS 페이지에서 HTTP 요청이 보안 문제를 초래한다.
→ HTTPS는 데이터를 암호화하여 중간에 도청, 변조하는 MITM 공격을 방지하는데, HTTP 요청이 혼합되면 다음 보안 위험들이 발생하게 된다.

  • 데이터 탈취 가능성
    • HTTP로 전송된 데이터는 암호화되지 않아, 공격자가 네트워크 중간에서 데이터를 가로챌 수 있다
    • ex) HTTP - 평문으로 전송된 데이터를 읽어버린다
  • 데이터 변조 가능성
    • HTTP로 로드된 리소스는 중간에서 변조될 수 있다
    • ex) HTTP로 로드된 JS에 악성 코드가 추가되어 있으면, HTTPS 페이지 전체가 위험에 노출된다.
  • HTTPS의 신뢰성 저하
    - 보안을 위해 HTTPS를 사용했지만, HTTP 리소스가 취약점이 되는 것이다.

브라우저에서 Mixed Content 에러는 어떻게 동작하지?

  1. HTTPS로 페이지 로드
    • 클라이언트(브라우저)가 HTTPS를 사용하여 웹 페이지를 요청한다
    • 브라우저는 TLS를 통해 데이터를 암호화하여 안전하게 로드한다
  2. HTTP 리소스 요청
    • 페이지에 JS, CSS, API 응답 등 HTTP로 된 리소스가 포함된 경우들을 감지한다
  3. 에러 발생
    • HTTP 요청이 발견되면 Mixed Content로 판단하여 동작한다
      → Active Mixed Content? → 차단, 에러 출력
      → Passive Mixed Content? → 경고, 필요 시 요청 허용

여기서 HTTP 리소스는 HTML, JS, CSS와 같은 프론트엔드나 이미지 URL 같은 요소들 뿐만 아니라 외부 API(백엔드 API, 오픈 API 등) 모든 HTTP로 이루어지는 요청들이다.

백엔드 API의 응답 역시 HTTP로 통신하면 데이터가 평문으로 전달되기 때문에 얼마든지 탈취될 수 있다.

나는 왜 React 서버만 HTTPS로 배포했지?

SKUPLATE 프로젝트를 배포할 때, React 파일과 Express 파일 모두 AWS EC2에 배포를 했었다.
오픈 톡방에 프론트엔드 개발자 선배님께 물어보니 SKUPLATE처럼 CSR(Client Side Rendering)으로 운영되는 프로젝트는 일반적으로 S3와 CloudFront(AWS의 Content Delivery Network 서비스)로 배포를 해서 인스턴스를 할당할 필요는 없었다고 한다.

내가 접근을 잘못하고 있었다는 것을 깨달았던 것을 그 때 알았으면 좋았을 것을... *

EC2 인스턴스에 배포를 한 나는 해당 서버에 React 빌드 파일이 실행되어 브라우저에 사용자가 요청한 리소스(HTML, CSS, JS 등)들을 전달한다고 생각했다. 그리고 Express 서버로 API 요청을 보내는 것 또한 React가 배포되어 있는 서버라고 생각을 했다.

그렇기 떄문에 내가 생각하는 대로, 눈에 보이는대로 사용자가 직접 마주하는 부분에 대해서 HTTPS로 처리하면 된다고 생각했기에 React를 올려둔 서버에만 TLS 인증서를 발급 받았었다.
그리고 Express를 배포한 EC2 인스턴스의 IP와 도메인을 노출시키지 않는다면 HTTP로 API 요청에 대한 응답을 받아와도 된다고 생각을 했다.

결국 나를 반겨준 것은 빨갛게 빛을 내고 있는 Mixed Content 에러였다.

Mixed Content: The page at 'https://skuplate.com' was loaded over HTTPS, 
but requested an insecure resource 'http://express_server_domain_이었던_것.com'. 
This request has been blocked; the content must be served over HTTPS.

브라우저는 HTTPS로 React 서버에 웹 페이지 리소스들을 요청했고,
브라우저에 올라온 리소스들에서 동적 리소스가 있을 때, HTTP로 Express 서버에 API 요청을 보냈다.
결국 HTTPS 페이지에 HTTP 리소스(API 응답)가 로드되는 것을 감지하여 에러를 발생한 것이다.

내가 해결한 방법은?

API 응답도 안전하게 브라우저에게 전달할 수 있도록, Express 서버를 올려둔 EC2 인스턴스에 Nginx를 Reverse Proxy로 설정하고,
Let's Encrpyt에서 TLS 인증서를 발급받아 Nginx에서 HTTPS로 들어온 요청(port 443)을 처리한 뒤,
내부적으로 HTTP 요청(port 80)을 Express 서버 (port 3000)으로 전달하도록 구성했다.

이 외에도 HTML 헤더에 meta 정보를 설정하는 등 다른 방법들도 있는 것 같은데, 나는 모두 인증서를 발급 받아서 HTTPS로 설정하는 게 안전할 것이라 생각했다.

그렇게 Mixed Content 에러와 작별할 수 있었다.

결론

Mixed Content 에러는 HTTPS와 HTTP가 만날 때 발생한다.
에러가 발생하여 브라우저가 차단까지 할 정도라면, HTTPS를 쓰는 의미가 없다고 알려주고 있는 것이다.
침착하게 모두 HTTPS로 바꿔주자.

Mixed Conent 에러 해결하자마자 CORS 정책도 터졌는데 이건 다음 글에 이어서 다루겠다.

참고 및 출처

https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content

https://m.blog.naver.com/on21life/222007672517

profile
이로운 개발자

0개의 댓글