학습 동기

프로젝트를 진행하며 사용자에게 로그인을 유지시켜 주기 위해서 JWT 를 사용한 적이 있어요. 그 때 인증과 인가의 개념을 헷갈렸던 기억이 있어서 다시한번 복기 할 겸 정리해보기로 했습니다.

인증

인증 단계에서는 사용자의 신원을 확인하는 단계입니다. 처음 회사에 들어가면 회사 사람인지 확인하고 출입증을 주는 행위를 신원확인 단계라고 할 수 있을 것 같아요. 핸드폰 FaceID 로도 핸드폰의 주인이 맞는지 인증하는 것도 예시로 들 수 있을 것 같아요. ㅎㅎ

서버에서 인증 처리는 다양하게 쿠키, 세션, 토큰 등등 으로 할 수 있는데요. 위 세가지의 특성에 대해서 알아보겠습니다.

쿠키, 세션, 토큰의 등장 배경!

통신을 할 때 과거 히스토리까지 전부 담에서 네트워크를 넘나들면 요청 자체가 너무 무거워지고, 해당 기록이 유실될 경우 원활한 통신이 어렵기 때문에 HTTP 통신은 무상태성(statusless)이라는 특징을 가지고 있어요. 비연결성도 하나의 특징이랍니다. 이렇게 된다면 모든 요청 때 마다 ID ,PW 를 입력하여 사용자 인증을 해야하는 불편함이 생길거예요. 그래서 이런 부분들을 해소하기 위해서 쿠키, 세션, 토큰이 등장하기 시작했어요.

쿠키

쿠키는 사용자 정보를 사용자의 브라우저에 저장시키는데요. 서버는 클라이언트의 로그인 요청에 대한 응답을 작성할 때 클라이언트 측에 저장하고 싶은 정보를 set-cookie 에 담아 놓습니다. 간편한 쿠키 발행과 연결 유지라는 장점이 있으나, 쿠키가 탈취되면 사용자의 정보도 탈취되고, 사용자인 척 서비스에 접근해 특정 작업을 수행할 수 있으니 보안에 취약하다는 단점이 있습니다.

세션

위에 사용자 정보 탈취라는 문제를 해결하기 위해서 세션은 비밀번호와 같은 인증번호를 쿠키에 저장하지 않고 사용자 식별자인 세션 ID를 저장합니다. 최초 로그인 시 서버에서 세션을 발급하여 세션 스토리지에 저장해두고, 요청이 들어왔을 때 올바른 세션 ID 인지 확인 후 로그인을 시켜주는 방식입니다. 세션은 서버에 저장되기 때문에 사용자가 수만명으로 늘어난다면 서버에 부하가 갈 수 있고 분산 DB 환경에서 세션 유실이 일어날 수도 있습니다.

토큰

토큰은 DB에 데이터를 저장하는 것이 아니라 토큰 자체에 사용자 고유 식별값을 넣어서 모든 요청시 토큰을 주고 받으면서 인증 처리를 합니다.

토큰은 머리(header), 가슴(payload), 배(signature) 로 나눠지며 헤더에는 사용자 고유정보를 암호화할 알고리즘이 무엇인지 담고 있어요. 페어로드에는 사용자 고유 값과, 주고 받고 싶은 내용, 만료 시간 등이 있고요. 시그니처는 사용자가 발급한 주체를 명시하는 내용이에요.

정리하면 페이로그에 있는 내용을 시그니처와 섞어서 헤더에 있는 암호 알고리즘으로 암호화 한 내용을 담은것이 토큰이라고 합니다.

토큰 장점

  • 시그니처를 알 수 없다면 위변조를 막을 수 없어요.
  • 인증 정보에 대한 별도의 관리가 필요 없어요.
  • 토큰이 한번 발급되면 만료될 때까지 사용할 수 있어요.

토큰의 단점

  • 쿠키, 세션과 마찬가지로 탈취되면 위험해요.
  • 강제로 토큰을 만료시켜버릴 수 없기 때문에 만료 시간을 짧게 가져야해요.
  • 페이로드에는 중요한 정보를 담으면 안된다.

해결 방법

  • 리프레쉬 토큰

    토큰과 리프레쉬 토큰을 함께 발급하고, 리프레쉬 토큰은 서버에 저장해두었다가 토큰이 만료되면 리프레쉬 토큰을 확인하여 토큰을 새로 발급해준다.

  • Sliding Session

    지속적으로 사용하고 있는 사용자에게 만료기간을 늘려준다.


인가

사용자를 식별했다면, 사용자의 권한에 따른 접근 허가도 필수인데요. 예를 들면 관리자 권한이 있는 사람만 일반 사용자의 데이터를 전체 다 볼 수 있게한다던가. 로그인을 한 사용자가 사장님인지, 손님인지에 따라서 사장님 페이지에 접근을 할 수 있는 권한을 주는 등 권한을 부여하는 것을 인가라고 합니다.

토큰을 사용한 인가 방식

토큰의 페이로드 부분에 사용자 식별자 외에도 다른 데이터를 넣을 수 있는데요! 이 점을 활용해서 사용자의 권한 정보를 함께 넣어두고 토큰이 유효한지 확인할 때, 페이로드를 디코딩하여 권한 검증까지 함께 할 수 있습니다.

이전에 프로젝트 할 당시 페이로드에 사용자 권한 정보를 넣어두고 그 값을 Spring RequestScope 에 담아서 요청에 대한 권한 확인이 필요할 때마다 그 값이 권한이 있는지를 확인하는 작업들을 했었어요. 그 작업들은 Spring AOP 를 사용하여 OnlyAdmin 과 같이 어노테이션 기반으로 동작가능하게 했어요.

느낀점

간단하게 인증은 사용자를 식별하는 것, 인가는 사용자의 권한을 부여하는 행위라고 이해하고 있었는데, 구체적인 장단점을 떠올려보니 다음 작업을 할 때에 더 이유있는 코드를 작성할 수 있을 것 같아요.