배움장 - 0tak

2023년 2월 19일의 배움

2023-02-19

서블릿 끝 정처기 끝

쉽지 않은 한 주였다. 생전 처음 공부하는 서블릿으로 게시판을 구현하는 미니 프로젝트를 진행했고, 동시에 정보처리기사 필기 시험도 준비해야 했다. 그래도 결과적으로 스무스하게 넘어가서 다행이다.

서블릿에서의 CORS 처리

얼른 정처기 공부를 하려고 급하게 게시판을 만들어놨더니, 교수님께서 만들어놨던 뷰(MVC의 V)를 다 떼어내고, Vue.js로 프론트엔드를 새로 짜보라고 하셨다. (아… 요구사항 분석과 변경 처리의 어려움을 강조했던 정처기 기본서의 한 페이지가 생각났다…)

프론트엔드를 새로 짜는 것은 그렇다 쳐도, 프론트엔드 서버와 백엔드 서버가 따로 기동될 수 있도록 CORS 통신을 가능하게 짜도록 주문하셔서 쉽지 않았다. 원래는 프론트 개발 서버에 프록시를 설정해서 SOP 제한을 넘기려고 했던 참이었다…

그렇지만 수긍하고 여러 자료를 찾아보기 시작했다. 실제로 프론트엔드 서버와 백엔드 서버를 나누는 경우가 현업에서도 적지 않은 것으로 알고 있고, 특히나 MSA를 적용하는 몇몇 서비스의 구조도에 프론트 서버가 다른 단위와 함께 따로 나타나있는 것을 본 기억이 있기 때문이다. 공부가 될 것이라고 생각했고, 실제로 많은 공부가 되었다.

CORS에 관해서 여려 문서를 찾아보면서 이론적인 부분을 공부하고, 서블릿으로 CORS 처리를 하는 사례를 찾아봤다. CORS의 구체적인 목적과 절차는 어떻게 되는지, 또 실제로 처리해줘야 하는 작업이 무엇인지 이론적 배경을 잡는 데에는 MDN 문서가 큰 도움이 되었다. 정확한 스펙은 WHATWG의 Fetch Standard에 기술되어 있다.

서블릿에서는 CORS 처리를 위해 필터를 사용하는 사례가 많은 것 같다. 지정한 URL 패턴에 해당하는 모든 요청을 인터셉트하여 CORS에 필요한 헤더를 붙여주는 방식이다. 필터를 사용하지 않는다면 매 서블릿에서 수동으로 헤더를 붙여줘야 할 것이다. 스택오버플로우에서 구현 사례를 찾을 수 있었고 많은 도움이 되었다.

다만 위의 코드를 그대로 사용하면 요청에 쿠키가 붙지 않는다. CORS 요청에는 기본적으로 인증 정보 (Credentials)가 무시된다. 여기서 인증 정보란, HTTP cookies, TLS client certificates, Authentication entries를 말한다. (자세히)

그러나 이번 프로젝트의 경우 서블릿 단에서 세션을 사용했고, 세션 처리를 위해서는 클라이언트가 자신의 세션 아이디를 쿠키로 갖고 있어야 하기 때문에, 인증 정보가 무시되면 곤란했다. 이를 해결하기 위해서는 클라이언트 측이 HttpXMLRequest를 통해 요청을 할 때, withCredential 옵션을 지정해야 하고, 백엔드에서도 Access-Control-Allow-Credentials 헤더의 값을 true로 지정하여 반환해줘야 한다.

또한 다른 Access-Control-Allow-… 헤더를 지정할 때 그 값을 ‘*‘로 지정해서도 안된다. 스택오버플로우에서 찾은 필터 코드에는 Access-Control-Allow-Headers의 값이 ‘*‘로 되어 있었기 때문에 Access-Control-Allow-Credentials 헤더를 줘도 쿠키가 유지되지 않았다. 이 문제 때문에 골치를 많이 앓았다.

실제 구현 코드는 여기에서 볼 수 있다.