안녕하세요!
최근 서버 개발을 하면서 발생했던 트러블 슈팅과 왜, 무엇이 원인이였는지 공유하고자 합니다.
현 상황은 이러했습니다.
사용자는 HTTPS로 웹 애플리케이션에 접속하여 일명 PRG(Post Redirect Get) 프로세스를 진행하고 있었습니다.
Post 요청 후 Spring Boot 애플리케이션은 사용자를 결과 페이지로 리디렉션하도록 설계되어 있었습니다.
그러나 사용자가 Safari 브라우저를 사용할 때는 아래의 사진처럼 '사파리가 해당 페이지를 열 수 없습니다. 네트워크에 연결할 수 없습니다' 라는 메시지가 표시되는 문제가 발생했습니다. 다른 브라우저에서는 문제가 없었지만, 유독 Safari에서만 이런 현상이 나타났습니다.
제가 개발하고 있던 서버 아키텍처는 다음과 같았습니다.
[클라이언트] ──HTTPS──> [Nginx] ──HTTP──> [Spring Boot]
클라이언트는 HTTPS로 서버에 접속을 시도 합니다. 서버 내부에서는 Nginx의 리버스 프록시를 사용해 Spring Boot 서버에 HTTP로 요청을 전달하고 있었죠.
그럼 왜 이런 문제가 발생했을까?
✅ 1.구조상 문제: 리버스 프록시 구조
- 클라이언트는 HTTPS로 접속함
- 하지만 Nginx는 내부에서 Spring Boot에 HTTP로 요청을 전달함
- Spring Boot는 받은 요청만 보고 판단하기 때문에 "아 이거 HTTP 요청이네?"라고 착각하고 http://로 리디렉션 생성
✅ 2.Spring Boot의 오판
Spring Boot가 기본적으로 보는 정보는 HttpServletRequest.getSchme()인데, 이걸 Nginx가 넘기지 않으면 무조건 HTTP로 인식합니다.
즉,
- 클라이언트는 https://example.com/submit로 들어왔는데
- Spring은 그냥 HTTP 요청이라고 착각해서
- redirect:/result → http://example.com/result 리디렉션 했던 것이죠
// 문제 상황 코드 예시
@PostMapping("/submit")
public String submit() {
// 로직 처리...
return "redirect:/result"; // Spring Boot가 http://example.com/result로 리디렉션
}
✅ 3.Safari의 강력한 보안 정책
Safari는 보안 강등(downgrade)을 적극적으로 차단한다고 합니다.
"지금 HTTPS에서 왔는데, 너 왜 HTTP로 보내려고 해? 이거 위험한데??"
→ 해당 페이지를 열 수 없습니다 에러 발생
그럼 이제 어떻게 해결했는지 알아보겠습니다.
해결방법
✅ 1. Nginx 설정
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $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; # ✅ 이 설정이 핵심!
}
- 클라이언트가 https://로 접속했는지 http://로 접속했는지를 $scheme 변수에 담고
- 이걸 X-Forwarded-Proto라는 헤더로 Spring Boot에 전달함
✅ 2. Spring Boot 설정
# application.yml
server:
forward-headers-strategy: framework
- 이건 Spring Boot가 X-Forwarded-* 헤더를 신뢰하고 활용하겠다는 의미
- HttpServletRequest.getScheme() 호출 시 → 이 값을 헤더로부터 파싱함
- 그 결과: 리디렉션 시 https://가 유지됨
추가 설명: 그래서 X-Forwarded-Proto가 뭔데?
📌 정의:
클라이언트가 원래 사용한 프로토콜 (HTTP 또는 HTTPS)을 프록시 서버(Nginx 등)가 백엔드 서버에게 전달하기 위해 사용하는 HTTP 헤더.
즉, 사용자가 실제로 http://로 요청했는지, https://로 요청했는지를 백엔드가 알 수 있게 알려주는 신호 입니다.
🧩 구조 예시:
🔹 사용자가 https://myapp.com/login으로 요청
GET /login HTTP/1.1
Host: myapp.com
🔹 Nginx는 이걸 받고, 내부적으로 Spring Boot에게는 이렇게 보냄:
GET /login HTTP/1.1
Host: myapp.com
X-Forwarded-Proto: https
X-Real-IP: 1.2.3.4
X-Forwarded-For: 1.2.3.4
이때 X-Forwarded-Proto: https ← 이게 핵심입니다.
Spring Boot는 이걸 보고 "아~ 클라이언트는 HTTPS로 요청했구나!" 라고 알 수 있는거죠.
최종 결과
이 두 가지 설정을 적용한 결과, Safari에서도 정상적으로 HTTPS 리디렉션이 이루어졌으며 문제가 완전히 해결되었습니다.
저와 비슷한 문제를 겪는 분들은 위 설정을 따라 해보시길 바랍니다.
감사합니다.
'Error Log' 카테고리의 다른 글
[Swagger] 스웨거 오류: Unable to render this definitionThe provided definition does not specify a valid version field. (0) | 2024.12.03 |
---|---|
[Querydsl] No sources given 에러 (0) | 2024.12.01 |