📌 들어가며
백엔드 개발자로서 피할 수 없는 개발 영역 중 하나가 session 혹은 token을 이용한 사용자 인증/인가 방식에 대한 개발 부분입니다. 해당 부분은 개인정보와도 밀접하게 연관되어 있는 부분이고 보안사항에서도 중요한 부분입니다. 만약 잘못될 경우 A 사용자의 화면에서 B 사용자의 정보가 담긴 화면이 보이는 등 큰 사고로 이어질 수 있습니다.(이런 사례가 발생하여 사용자가 언론제보 및 신고할 경우... 개인정보 탈취 등과 관련하여 회사는 큰 고초를 겪게 될 수 있습니다..😂)
이처럼 인증과 인가 부분은 매우 중요한 개발 영역이라고 할 수 있습니다. 불행인지 다행인지.. 저는 아직 입사 이후 '인증'관련 도메인은 개발해 본 적이 없어 대략적으로 회원 인증하는 절차에 대해서만 알고 있었는데요.. 그래도 인증관련은 꽤나 중요한 부분인만큼 오늘 포스트를 통해 정리해보는 시간을 가지고자 합니다.
📌 인증과 인가
많은 사람들이 헷갈려 하는 부분이 인증 과 인가를 같은 것으로 생각하는 것입니다. 둘은 엄밀히 차이가 있는 것으로 지금부터 그 차이를 알아보도록 하겠습니다.
📌 인증 (Authentication)
인증은 사용자가 로그인을 하는 행위로 이해하면 좋습니다. 어떠한 사용자가 아이디와 패스워드를 입력하여 로그인을 시도할 때 이 사용자가 회원 DB에 등록되어 있는 사용자임을 서버에서 확인하는 절차를 '인증' 이라고 합니다.
📌 인가 (Authorization)
인가는 쉽게 표현하면 인증 절차를 거쳐 로그인한 사용자에 대해 권한을 확인하는 것입니다.
사용자 A와 사용자 B가 있을 때 사용자 A는 글 작성, 수정, 삭제에 대한 권한이 있지만 사용자 B의 글에 대한 수정 이나 삭제에 대한 권한은 없고 두 사용자 모두 관리자 페이지에는 접근되지 않을 것입니다. 이처럼 특정 사용자의 서버 자원에 대한 접근 확인 절차를 의미합니다.
📌 HTTP의 비상태성 (Stateless)
HTTP는 비상태성이라는 특성을 갖고 있습니다. 서버는 클라이언트의 상태를 저장하지 않아 클라이언트의 상태를 알 수 없습니다. 이로 인해, 이전 요청과 다음 요청의 맥락이 이어지지 않습니다. HTTP 단독으로는 요청한 클라이언트가 이전에 이미 인증과정을 거친 HTTP 요청인지 알 수 없습니다. 그렇다고, 글을 조회하거나 어떤 페이지에 접속할 때마다 사용자에게 로그인을 하여 인증절차를 수행하게 할 수는 없습니다. 웹 애플리케이션에서는 이 문제를 세션 또는 토큰을 사용하여 문제를 해결합니다. 즉, 세션과 토큰은 인증 보다는 인가와 관련된 기술이라고 할 수 있다.
📌 세션 방식 인증/인가
세션기반 인가는 사용자의 인증 정보가 서버의 세션 저장소에 저장되는 방식입니다. 서버의 세션 저장소로는 Redis를 사용할 수 있습니다.사용자가 로그인을 하면, 해당 인증 정보를 서버의 세션 저장소에 저장하고, 사용자에게는 저장된 세션 정보의 식별자인 Session ID를 발급해줍니다. 발급된 Session ID는 브라우저에 쿠키 형태로 저장되지만, 실제 인증 정보는 서버에 저장되어 있다. 브라우저는 인증 절차를 마친 이후의 모든 요청마다 HTTP Cookie 헤더에 Session ID 를 함께 서버로 전송합니다. 서버는 요청을 전달받고, Session ID에 해당하는 세션 정보가 세션 저장소에 존재한다면 해당 사용자를 인증된 사용자로 판단합니다.
📌 토큰 방식 인증/인가
세션 기반 인증과 토큰 기반 인증의 가장 큰 차이점은 세션 기반 인증 방식이 인증 정보를 서버가 갖고 있다면 토큰 기반 인증 방식은 인증 정보를 클라이언트가 가지고 있다는 것입니다. 이때 인증 정보가 토큰의 형태로 브라우저의 로컬 스토리지(혹은 쿠키)에 저장됩니다. 토큰의 종류에 따라 다르겠지만, 대표적인 토큰인 JWT의 경우(JWT 토큰을 가장 많이 사용합니다!) 디지털 서명이 존재해 토큰의 내용이 위변조 되었는지 서버측에서 확인할 수 있습니다. 토큰 기반 인증에서는 사용자가 가지고 있는 토큰을 API 요청 시 HTTP 의 Authorization 헤더에 실어 요청을 보냅니다. 이 헤더를 수신한 서버는 토큰이 위변조 되었거나, 만료 시각이 지나지 않은지 확인한 이후 토큰에 담겨있는 사용자 인증 정보를 확인해 사용자를 인가하게 됩니다.
📌 둘 중 어떤 인증방식을 사용해야 할까?
✔️ 사이즈
세션의 경우 Cookie 헤더에 세션 id만 실어 보내기 때문에 트래픽을 적게 사용합니다. 그러나 jwt 토큰 인증 방식의 경우 사용자 인증 정보와 토큰의 발급시각, 만료시각, 토큰의 ID등 담겨있는 정보가 세션 ID에 비해 많으므로 세션 방식보다 훨씬 더 많은 네트워크 트래픽을 사용하게 됩니다.
✔️ 안전성과 보안성
세션의 경우 모든 인증 정보를 서버의 세션 저장소에서 관리하기 때문에 보안 측면에서 조금 더 유리하다고 볼 수 있습니다. 설령 세션 ID가 해커에게 탈취된다고 하더라도, 서버측에서 해당 세션을 무효 처리하면 해커는 해당 세션 id를 통해 할 수 있는 것이 없습니다. 하지만 토큰의 경우 토큰은 서버가 트래킹하지 않고, 클라이언트가 모든 인증정보를 가지고 있습니다. 따라서 토큰이 한번 해커에게 탈취되면 해당 토큰이 만료되기 전까지는 해당 토큰을 이용한 해커에게 속수무책으로 피해를 입을 수 밖에 없습니다.
또한 JWT 특성상 토큰에 실린 Payload가 별도로 암호화 되어있지 않으므로, 누구나 내용을 확인할 수 있습니다. 따라서 Payload에 민감한 데이터는 실을 수 없습니다. 즉, Payload 에 실을 수 있는 데이터가 제한되게 됩니다. 하지만 세션과 같은 경우에는 해당 id에 대한 모든 데이터가 서버에 저장되기 때문에 아무나 함부로 열람할 수 없으므로 저장할 수 있는 데이터에 제한이 없습니다.
✔️ 확장성
사실 위의 두 가지 측면만 보면 토큰 방식을 사용할 이유가 없어 보이기도 합니다. 그러면 그냥 세션 인증방식을 사용하면 되는거 아니야? 라고 할 수 있지만 그럼에도 불구하고 요즘 jwt 토큰 방식을 많이 사용하는 이유는 바로 이 확장성에 있습니다.
일반적으로 웹 애플리케이션의 경우 서버 확장 방식으로 수평 확장 방식을 택하게 됩니다. 즉 수많은 트래픽 요청을 여러 대의 서버가 처리하는 것인데요 이 때 별도의 작업을 해주지 않으면 다른 서버로 들어간 동일한 사용자의 요청이 세션 불일치 현상을 겪을 수 있습니다. 이를 해결하기 위해서 각 서버마다 Sticky Session, Session Clustering, 세션 스토리지 외부 분리 등의 작업을 해주어야합니다.
그러나, 토큰 기반 인증 방식의 경우 서버가 직접 인증 방식을 저장하지 않고, 클라이언트가 저장하고 있다가 요청하는 방식을 취하기 때문에 이런 세션 불일치 문제로부터 자유롭습니다. 이런 특징으로 토큰 기반 인증 방식은 HTTP의 비상태성(Stateless)를 그대로 활용할 수 있고, 따라서 높은 확장성을 가지게 됩니다. 서비스의 성장으로 인해 높은 확장성을 원하는 많은 IT 기업들에서 원하는 인증 방식이라고 할 수 있습니다.
✔️ 서버의 부담
세션 기반 인증 방식은 서비스가 세션 데이터를 직접 저장하고, 관리한다. 따라서 활성 회원수가 늘어나고 관리해야 하는 세션 데이터의 양이 많아지면 많아질수록 서버의 부담이 증가할 것입니다. 하지만 토근 기반 인증 방식은 서버가 인증 데이터를 가지고 있는 대신, 클라이언트가 인증 데이터를 직접 가지고 있습니다. 이로 인해 유저의 수가 많이 늘어나게 되더라도 늘어나느 유저 수 만큼 서버의 부담이 증가하지 않습니다. 따라서 서버의 부담 측면에서는 세션 기반 인증 방식보다는 토큰 기반 인증 방식이 조금 더 유리할 수 있습니다.
결국 어떠한 방식으로 인증/인가를 진행할지는 현재 서비스를 제공하는 회사의 상황에 맞게 선택하면 될 것 같습니다. 두 가지 방식 모두 장단점이 있으며 서버의 부담과 같은 문제는 비용을 충분히 감당 할 수 있는 규모의 회사라면 괜찮치 않을까 싶습니다. 그렇지만 만약 비용 절감이 목표라면 토큰 인증방식이 더 좋을 수 있습니다.
참고 : https://hudi.blog/session-based-auth-vs-token-based-auth/
'개발은 개념싸움이야🫠' 카테고리의 다른 글
[DB] 트랜잭션(transaction) 과 격리성 수준 (2) | 2023.10.23 |
---|---|
CQRS 란 무엇인가 (0) | 2023.03.11 |
Refresh Token 이란 (0) | 2023.02.18 |
객체란 무엇인가 - 객체(object), 클래스(class) , 인스턴스(instance) (1) | 2023.02.02 |