본문 바로가기
TroublesShooting

[Apache/Tomcat] 웹 서버 에러 페이지 처리(ErrorDocument) 시 로그인 세션이 끊기는 문제 해결기

by JINJINC 2026. 5. 26.
728x90
반응형

1. 개요 (문제 상황)

최근 주요 웹 시스템 보안 점검 항목 중 하나인 "웹 서버 및 WAS 정보 노출 차단"을 위해, 잘못된 URL(400, 404, 500 등) 요청 시 http 코드가 아예 알 수 없도록 커스텀 에러 페이지(error.html)를 보여주는 작업을 전산팀에서 진행했다.

전산팀 공유에 따르면, 처음에는 Tomcat단에서 처리하려 했으나 톰캣에 설정해준 error 페이지가 제대로 적용되지 않아서, 이를 해결하기 위해 전산팀에서는 앞단 웹 서버(Apache)에서 에러를 가로채도록 ProxyErrorOverride On 설정을 적용했다는 답변을 받았다. 

문제는 이 인프라 설정이 적용된 후, 애플리케이션 단에서 잘 되던 로그인 세션이 유지되지 않고 자꾸 튕기는 사이드 이펙트가 발생한 점이다.

 

2. 원인 분석: ProxyErrorOverride On과 세션 유실

개발자 관점에서 왜 ProxyErrorOverride On 설정이 잘 작동하던 로그인을 터뜨렸는지 아파치와 톰캣의 연동 아키텍처 관점에서 분석해 보았다.

아파치 설정에서 ProxyErrorOverride On을 켜면, 웹 서버(Apache)는 WAS(Tomcat)가 보내는 응답 중 에러나 비정상 코드가 포함된 것을 감시하고 가로채는 역할을 한다. 문제는 이 설정이 활성화되면 사용자가 로그인을 성공했을 때 톰캣이 내보내는 302 Redirect 응답 및 세션 쿠키(JSESSIONID) 발행 과정에 아파치가 과도하게 개입하게 된다는 점이다.

아파치의 Override 기능이 응답 헤더 제어권을 흔들면서 브라우저에 세션 쿠키가 정상적으로 구워지지 않는 현상이 발생했고, 결과적으로 사용자는 로그인을 해도 다음 페이지로 넘어가는 순간 세션이 풀려버리게 되었다.

이 현상의 실마리를 풀기 위해 단계별로 원인을 좁혀나갔다.

① 로고 데이터 누락으로 인한 404 추적

처음에는 애플리케이션 내 특정 페이지에 로고 이미지 파일이 없어서 보이지 않는 404 Not Found 에러가 먼저 터진 것이 원인 아닐까 의심했다. 이미지 파일 누락으로 발생한 404 응답을 아파치가 가로채는 과정에서 로그인 세션 헤더까지 같이 꼬였을 가능성이 있었기 때문이다. 이에 따라 톰캣 서버 내부의 에러 페이지 경로와 누락된 로고 파일 부분을 정상적으로 수정해 주었으나, 아쉽게도 로그인이 풀리는 문제는 여전히 지속되었다.

② 톰캣 server.xml 수정과 한계 직면

그다음으로 WAS 자체에서 정보를 숨기기 위해 톰캣 설정을 수정해 보았다. server.xml을 열어 에러 리포트 밸브(ErrorReportValve) 설정을 추가하고, 상세 이력이나 스택 트레이스가 노출되지 않도록 showReport="false", showServerInfo="false" 조치를 취했다.

이 조치로 톰캣 버전 정보 등은 숨길 수 있었지만, 시스템 에러 시 나타나는 하얀 화면과 HTTP 상태 코드(404 등) 자체는 여전히 브라우저에 노출되었기 때문에 "HTTP 코드가 아예 노출되지 않도록 처리하라"는 보안 점검 기준을 완전히 충족하기에는 한계가 있었다.

결국 아파치 단에서 ProxyErrorOverride On을 유지하되, 세션 유실 사이드 이펙트를 막을 수 있는 '웹 서버 레벨의 정밀한 설정 보정'이 강제되는 상황임을 인지하게 되었다.

3. 트러블슈팅: 설정 보정

애플리케이션의 가용성을 확보하면서 보안 점검 기준을 충족하기 위해, 전산팀이 작성한 아파치 가상 호스트(ssl.conf) 설정을 검토하며 두 가지 핵심적인 보정 작업을 진행했다.

 

① 톰캣(Tomcat) 레벨에서의 최후의 보루 설정

앞단(Apache)에서 에러를 가로채더라도, 프록시 설정 변경 중 사각지대가 생기거나 예측하지 못한 방식으로 에러가 WAS에 직접 도달할 수 있다. 이때 톰캣 자체 보안 설정이 없으면 최후의 방어선이 무너지며 버전 정보(Apache Tomcat/x.x.x)가 노출된다. 인프라 보안의 핵심인 다중 방어(Defense in Depth)를 위해 아래 설정을 완료했다.

  • server.xml 수정 (에러 리포트 밸브 설정)
    • 경로: 톰캣_홈/conf/server.xml
    • 내용: <Host> 태그 내부에 아래 Valve 설정을 추가하여 버전 및 상세 스택 트레이스 노출을 차단했다.
    XML
     
    <Valve className="org.apache.catalina.valves.ErrorReportValve"
           showReport="false"
           showServerInfo="false" />
    
    • showServerInfo="false": 에러 화면 최하단의 톰캣 버전 정보 출력을 숨김.
    • showReport="false": 에러의 구체적인 내용 및 스택 트레이스 문구를 숨김.
  • web.xml 수정 (글로벌 커스텀 에러 페이지 매핑)
    • 경로: 톰캣_홈/conf/web.xml
    • 내용: 존재하지 않는 페이지(404)나 내부 서버 오류(500) 발생 시, 톰캣 기본 뼈대 화면 대신 공통 에러 페이지로 포워딩되도록 매핑을 지정했다.
    XML
     
    <error-page>
        <error-code>400</error-code>
        <location>/error.html</location>
    </error-page>
    <error-page>
        <error-code>404</error-code>
        <location>/error.html</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/error.html</location>
    </error-page>
    
    (다만, 이 설정들만으로는 HTTP 상태 코드 자체를 숨기거나 특정 .jsp 에러 제어권을 완벽히 통제하는 데 한계가 있어 앞단 웹 서버의 보정이 함께 필요했다.)

② 아파치(Apache) 레벨에서의 세션 및 경로 보정

세션 유실 문제를 해결하기 위해 전산팀과 협업하여 가상 호스트 설정을 다음과 같이 보정했다.

  • 세션 유지를 위한 ProxyPassReverseCookiePath 추가 아파치가 톰캣으로부터 받은 쿠키 경로를 브라우저에 정확히 전달할 수 있도록 세션 경로를 강제로 매핑해주는 옵션을 추가했다.
  • 특정 서비스 경로(<Location>)로 범위 제한 서버 전체에 설정을 걸면 위험하므로, 문제가 되는 특정 서비스 컨텍스트인 <Location "/service"> 블록 내부로 설정을 격리하여 안정성을 높였다.

 

 

4. 최종 반영된 아파치 가상 호스트 설정

전산팀과 논의하여 최종적으로 안착시킨 아파치 설정(ssl.conf/ vhost.conf)의 핵심 블록이다.

 

<Location "/service">
    # 1. 오리지널 Host 헤더를 WAS로 전달하여 세션 기반 검증 통과 유도
    ProxyPreserveHost On
    
    # 2. 톰캣의 에러 응답을 아파치가 가로채도록 활성화
    ProxyErrorOverride On
    
    # 3. 중요: 톰캣이 발급한 쿠키 경로(/)를 프록시 경로(/kbif)와 일치시켜 세션 유실 방지
    ProxyPassReverseCookiePath / /service
    
    # 4. 보안 점검 대응: 에러 발생 시 커스텀 에러 페이지 매핑
    ErrorDocument 400 /service/error.html
    ErrorDocument 403 /service/error.html
    ErrorDocument 404 /service/error.html
    ErrorDocument 500 /service/error.html
</Location>

 

(참고: ErrorDocument 지정 시 경로 앞에 프록시 컨텍스트인 /service를 정확히 붙여주어야 아파치가 무한 루프에 빠지지 않고 해당 파일을 올바르게 찾아 브라우저에 뿌려준다.)

 

 

💡 설정 과정에서의 삐끗했던 순간들 (삽질 기록)

인프라 설정 파일(conf)은 단 하나의 글자 오타나 공백도 허용하지 않는다는 것을 이번에 뼈저리게 배웠다.

  • 명령어 오타: 세션 경로를 잡기 위해 설정을 넣었는데 아파치가 죽어버렸다. 로그를 보니 ProxyPassReverseCookiePath에서 알파벳 e를 빼먹고 ProxyPassReverseCookiPath로 적었던 것.
  • 유령 공백(\xc2\xa0): 에러 페이지 경로를 깔끔하게 정돈하는 과정에서 웹 페이지의 텍스트를 복사·붙여넣기했더니 눈에 보이지 않는 특수 공백 문자가 섞여 들어왔다. 아파치가 invalid command '\xc2\xa0' 에러를 내뿜는 것을 보고, 설정 파일은 가급적 '직접 타이핑'하거나 공백을 완전히 지운 뒤 재입력해야 안전하다는 교훈을 얻었다.

5. 결과 및 교훈: 왜 톰캣과 아파치 설정을 둘 다 유지해야 했을까?

모든 오타와 공백 문제를 해결하고 아파치 문법 검사(apachectl configtest)를 거쳐 서버를 재시작했다. 결과는 대성공이었다.

  1. 로그인 세션이 풀리지 않고 짱짱하게 잘 유지된다.
  2. 존재하지 않는 .jsp 경로를 억지로 대입해 보아도, 톰캣의 404 하얀 화면 대신 우리가 준비한 깔끔한 안내 화면(error.html)만 송출되어 보안 점검 요건을 완벽히 충족했다.

돌이켜보면 처음 진행했던 톰캣 설정(ErrorReportValve)과 전산팀의 아파치 설정 중 어느 하나도 무의미한 것은 없었다. 만약 아파치 설정만 믿고 톰캣 설정을 원복했다면, 프록시가 우회되거나 예측하지 못한 사각지대로 에러가 발생했을 때 최후의 보루인 톰캣 버전 정보가 그대로 노출되었을 것이다.

또한 사용자가 HTTP(80)로 들어올지 HTTPS(443)로 들어올지 알 수 없기에 vhost.conf와 ssl.conf 두 곳 모두에 동일하게 촘촘한 방어벽을 세워야 했다.

인프라 보안 설정은 시스템을 안전하게 만들지만, 때로는 이처럼 애플리케이션의 핵심 로직(세션, 쿠키, 리다이렉트)을 간섭하여 예기치 못한 장애를 만들기도 한다. 

전산팀과의 소통, 그리고 단계별 로그 분석을 통해 사이드 이펙트의 실타래를 풀어내는 과정이 얼마나 가치 있는지를 깊이 깨닫게 된 소중한 경험이었다.

 

728x90
반응형

댓글