누군가 나에게 왜 로그아웃을 POST로 해야되냐고 물어봤다. 생각해보니까 왜 그런지 나도 명확하게 말을 하지 못했다. rfc에 나온 정의를 바탕으로 그 근거를 찾아보자.
RFC 9110 §9.3.3에 따르면 POST는 “대상 리소스가 요청 본문에 담긴 표현을 리소스 고유의 의미에 따라 처리하도록 요청”하는 메서드다. 이 처리는 새 리소스를 만들 수도, 계산만 수행할 수도 있으며 반드시 상태를 변경할 필요는 없다.
핵심은 “리소스 고유 의미에 따른 처리”가 필요할 때 POST를 사용한다는 점이다. 리소스 고유 의미란, 해당 URI가 어떤 동작을 수행할지는 서버 애플리케이션이 정하는 영역이고, HTTP 표준은 관여하지 않는다는 말이다. 이 글에서 말하고자 하는 로그아웃 기능을 예로 들겠다. /logout은 세션 무효화를 해 서버 상태를 변경하지만, PUT이나 DELETE를 쓰긴 애매하다. 따라서, 해당하는 URI자체를 POST와 묶어서 하나의 함수로 보자는 뜻이다.
참고로 리소스를 실제로 생성한 경우 서버는 201 Created와 함께 Location 헤더를 보내는 것이 권장(should)된다. 생성이 없으면 200 OK 또는 204 No Content도 가능하다.
• 세션/토큰 무효화는 서버 상태 변경을 하기 때문에 safe 메서드인 GET은 부적합하다.
• GET /logout은 링크 프리뷰·브라우저 프리패치·캐시 재전송으로 사용자가 모르게 호출될 수 있어 CSRF · UX 문제가 발생할 수 있다.
GET은 safe + cacheable 로 설계됐다. 상태 변화를 일으키면
1) 캐시 재사용 (History navigation)
2) 자동 재시도 (네트워크 오류)
3) 프리패치/프리렌더
등으로 예기치 않은 로그아웃이 발생할 수 있다. 따라서 GET /logout은 규격·보안 모두에 어긋난다.