spring security를 이용해서 api 서버를 간단하게 만드는 토이 프로젝트를 진행하다가, 뭔가 거슬리는 것이 있어서 몇 가지 설정을 off 한 게 있었는데요. csrf도 그 중 하나였습니다. 3회 코딩테스트를 출제하느라 얼레벌레 넘어간 감이 있었는데요. 문득 생각이 난 김에 몇 편 정도 써 보려고 합니다.

 

 혹여나 이상한 부분이 있다면, 댓글을 남겨주시면 감사하겠습니다.

 

 


 먼저, spring security + spring web 디펜던시만 추가하고 아무것도 추가하지 않은 서버를 돌리면, 요런 로그인 페이지가 하나 뜨게 됩니다. 페이지 소스를 보겠습니다.

 

 보면 _csrf라고 hidden type이 하나 뜨게 되는데요. csrfFilter 클래스에서 doFilterInternal 메서드에 브레이크 포인트를 걸어보면, 해당 페이지가 뜨기 전에 브레이크가 걸리는 것을 볼 수 있어요. 왜 그런지는 잘 모르겠지만, 나름의 추론을 해 볼 수는 있습니다. 시큐리티 디폴트 웹 사이트에 csrf 토큰이 hidden type으로 박혀있었습니다. 그리고 doFilterInternal 메소드에 이런 로직이 있었는데요.

 

 

 이 부분을 잠깐 보면, Token이 없을 때, csrfToken을 새로 생성한다는 것만 보실 수 있습니다.

 

 

 그리고 일련의 과정을 통해, 로그인 페이지의 소스 코드에 _csrf가 히든으로 있다는 것을 볼 수 있는데요. 일련의 과정은 모르겠지만, 토큰을 발급한 서버에서, 클라이언트로 토큰이 날라갔다는 합리적인 추론은 해 볼 수 있습니다.

 

 


 몇 분이 지난 후에, 로그인을 해 보니 토큰 값이 바뀌어져 있었습니다. 이 부분은 다음에 따로 언급을 할 기회가 있을 듯 싶습니다.

 

 

 이제 디버깅을 할 때 저 value 값하고 Jsession 값을 집중해서 보도록 하겠습니다.

 

 

 로그인을 하면 csrfFilter가 걸리게 됩니다. 천천히 디버그를 하다 보면, session을 볼 수 있는데요. attributes에서 CsrfToken 부분이 보입니다. 이 부분을 보니, 5cf94f7c-... 이 부분이 보입니다. hidden type으로 넘기는 _csrf와 일치함을 볼 수 있어요.

 

 

 다음에, id 부분을 보면 16C23786... 어쩌고가 보이는데요.

 

 

 저장소의 쿠키 탭을 보면, JSESSIONID가 보여요. 16C23786... 어쩌고가 있음을 알 수 있어요. 여기서, 서버 내부에서는 csrf 토큰값을 저장함을 알 수 있어요. 그리고 쿠키가 jsessionid를 물고 왔는데, 이 16C23786...은 session에서 봤던 그 id 값과 동일합니다.

 

 


 만약에, 이 csrf token에 대한 정보를 클라이언트 측에서 넘겨주지 않으면 어떻게 될까요?

 

 

 doFilter 부분을 계속 보다 보면, actualToken 부분이 나오는데요. 이것은 요청이 들어왔을 때, csrfToken에 대한 정보를 따오기 위함입니다. 헤더로 넘어오거나, 아니면 form 형태로 넘어오거나 둘 중 하나의 형태로 받게 될 건데요.

 

 

 70번째 줄에서 csrfToken.getToken()은 이미 서버에 발급된 토큰을 의미합니다. 그리고 actualToken은 유저가 요청을 보낼 때 csrf에 관한 정보를 의미하는데요. post로 요청했기 때문에, 70번째 줄까지 내려와 버리게 됩니다.

 

 

 postman으로 요렇게 보내게 되면, csrf에 대한 정보가 비어 있어요. 서버 입장에서는 저 정보를 request를 받은 건데요. 계속 타고 내려오다가 70번째 줄에 걸리게 되는데요. csrf에 대한 정보가 없었기 때문에 검증이 실패하게 됩니다. 따라서, Filter를 타지 않고 접근을 거부하는 예외가 떨어지게 됩니다.