May
11th,
2021
사이드 프로젝트 개발 과정 중, 로그인 기능을 구현해야 했다. 현재 실무에서도 세션 기반으로 로그인을 구현하고 있지만, 이 방법 외에 토큰으로 적용하는 방법도 있다고 하여 두가지의 차이점과 장단점에 대해 알아보도록 한다.
세션/쿠키 인증방식
서버 측에서 사용자의 정보를 기억하는 방법이다. 사용자의 정보를 기억하기 위해 세션을 사용한다. 이 때 메모리나 디스크, 또는 DB등을 이용하는데 보통 Redis를 많이 사용한다.
세션/쿠키를 통한 인증 flow는 아래와 같다 :
- 사용자 로그인
- 서버에서 계정정보 검증 후 사용자의 고유한 ID 값을 부여하여 사용자 id와 매핑정보를 저장
- 응답으로 세션ID 발송
- 사용자는 서버에서 발급받은 세션ID를 쿠키에 저장한 후, 요청을 보낼 때 같이 전송
- 서버에서는 쿠키를 받아 세션 저장소에서 검증 후 대응되는 정보를 가져옴
장점
- 서버에서 관리하기 때문에 보안상 유리하다.(물론 해커가 훔친 쿠키를 이용해 HTTP 요청을 보낼 경우 서버는 사용자로 오인할 수 있기 때문에 HTTPS로 변경하거나 세션에 유효시간을 지정해주는 것이 좋다.)
- 쿠키를 통해 세션에 접근하면 세션 ID로 사용자를 구분할 수 있어 일일히 사용자 정보를 확인하지 않아도 된다.
단점
- 서버에 세션을 저장하기 때문에 사용자 수가 많아지면 서버의 부담이 늘어난다.
- 세션 서버를 두기로 한 경우, 그것에 대한 각각의 trade off를 따져 세션 서버를 선택해야 한다.(sticky세션이라는, 같은 서버에 세션을 계속 연결시키는 방식을 사용하여 해결할 수는 있다)
- 모바일 웹에서 로그인할 경우, 유동 IP에 따라 세션이 바뀌기 때문에 이동하면 로그인이 풀릴 수 있다.
- 쿠키는 단일 도메인 및 서브 도메인에서만 작동하도록 설계되어 여러 도메인에서 관리하기 번거롭다.
토큰 기반 인증방식
세션 기반 인증과는 다르게 서버가 사인한 토큰을 이용하여 인증을 수행하는 방식이다. 인증받은 사용자에게 토큰을 발급하고, 서버에 요청을 보낼 때 헤더에 토큰을 함꼐 보내 유효성 검사를 진행한다. 토큰 기반의 인증 flow는 아래와 같다 :
- 사용자 로그인
- 서버에서 계정정보 검증 후 Access Token(JWT) 발급하여 응답에 함께 발송
- 사용자는 AccessToken을 저장한 후, 서버에 요청할 때 Http 헤더에 해당 토큰을 함께 전송
- 서버에서 토큰을 검증하고 요청에 응답
장점
- 상태를 유지하지 않아(stateless) 서버확장이나 유지보수에 용이하다.
- 플랫폼간 권한 공유가 가능하여 토큰 기반으로 하는 다른 인증 시스템에 접근이 가능하다.(OAuth, facebook, google로 로그인 등)
- 쿠키를 전달하지 않기 떄문에 쿠키 사용에 의한 취약점이 사라진다.
- CORS 문제를 해결할 수 있다.
단점
- 요청 헤더가 길어지기 때문에 패킷의 크기가 커져 대역폭을 많이 사용하여 성능에 영향을 끼친다.
- 보안문제에 있어 세션방식에 비해 취약하다. XSS 공격 대비를 해주어야 한다.(토큰 탈취시 악의적인 사용자는 유효기간이 지나기 전까지 토큰을 사용해 정보를 탈취할 수 있다.)
JSON Web Token(JWT)
JSON Web Token은 인증 헤더 내에서 사용되는 토큰 포맷이다. 토큰은 Baase64로 인코딩한 String으로 이루어져 있다.
이 토큰은 두 개의 시스템끼리 안전한 방식으로 통신할 수 있도록 도와준다.
JWT의 가장 큰 장점은 계정 서버와 API 서버가 분리되어 있어도, API 서버가 계정 서버에게 토큰의 유효성을 묻지 않고도 스스로 판단할 수 있다는 것이다.
JWT 구조
JWT는 Header, Payload, Verify Signature로 이루어져 있다.
- Header : JWT인 토근의 유형이나 HMAC, SHA256 또는 RSA와 같이 어떤 해시 알고리즘을 사용했는지에 대한 정보가 담겨져있다.
- Payload : 클라이언트에 대한 정보나, meta Data에 관한 내용이 담겨져 있다.
- Signature : 토큰을 인코딩하거나 유효성 검증시 사용하는 고유한 암호화 코드이다. Header, Payload를 Base64로 인코딩한 값을 합친 후, 비밀키로 해시를 진행한다. 해당 해쉬 값은 Base64로 인코딩하여 생성한다.
JWT flow
- 사용자가 로그인을 한다.
- 서버에서 계정정보 검증 후, 사용자의 고유한 ID 값을 부여하고 기타 정보와 함께 Payload를 작성하여 암호화할 secret key를 통해 access token을 발급해 클라이언트에게 반환한다.
- 이후 사용자가 JWT가 요구되는 API를 요청할 때 클라이언트가 Authorization header에 Access Token을 담아 보낸다.
- 서버는 JWT의 Signature를 복호화하여 검증한 뒤, payload를 디코딩하여 사용자 정보를 확인한다.