쇼핑몰 프로젝트에서 로그인 기능을 구현하려는데
Session과 JWT 방법 중 무엇을 사용해야 하는가?
로그인 인증 기능이 왜 필요한가?
--
쇼핑몰에서 내 주문내역을 보고싶다면
로그인해서 내가 누구인지 알려주고 그 다음에 나의 주문내역을 확인해야한다.
- 로그인 페이지로 이동
- 아이디와 비밀번호를 입력하여 로그인
- 내 주문내역 페이지로 이동
- 주문내역 확인
이때 로그인을 계속 인증해주는 기능이 없다면
2번에서 로그인을 하고 다른 페이지로 이동하는 순간 내가 로그인을 했던 정보는 없어지게 된다.
그렇게 되면 4번에서 다시 로그인을 해줘서 나라는 것을 알려주고 나의 주문내역을 확인해야한다.
물론 내부적으로 로그인을 한 순간부터 다른 페이지로 이동할 때마다 로그인 정보를 함께 넘겨주는 코드를 작성하면 로그인 했던 정보는 없어지지 않고 계속 유지하게 될 것이다.
다만 이러한 방식을 사용하면 항상 내 정보의 데이터를 함께 요청하게 되어 보안에 취약할 것이다.
그래서 로그인을 한 순간부터 계속 로그인이 유지되어 매번 로그인을 해줄 필요없이 계속 유지해주는
로그인 인증 기능이 필요하다.
--
Session 방식
--
- 사용자(클라이언트)가 서버에게 로그인 요청
- 서버는 로그인 정보와 랜덤값 세션ID를 생성하여 세션 저장소(key, value)에 저장
- 서버는 클라이언트에게 세션 ID를 응답
- 이 후 사용자는 서버에게 요청할 때마다 해당 세션ID를 쿠키에 포함해서 전달하여 본임임을 인증한다.
- 서버는 쿠키에 포함된 세션ID를 가지고 세션 저장소에서 해당 정보를 찾아서 누구인지 알 수 있게 된다.
사용자가 로그인을 하면 로그인 정보와 해당 정보를 가리키는 세션 ID를 만들어서 세션 저장소(메모리)에 저장을 한다.
(이 때 세션ID는 UUID와 같이 랜덤값으로 생성한다.)
그리고 로그인 정보를 가리키는 세션 ID를 클라이언트에게 반환해준다.
그러면 이제 세션 ID는 나 자신을 인증하는 열쇠가 되는 것이다.
결과적으로 서버도 세션 ID를 가지고 있고 사용자도 세션 ID를 가지고 있게 된다.
세션 ID를 받은 사용자는 그 다음부터 다른 페이지로 이동할 때마다 이전에 받은 세션 ID를 쿠키에 담아서 전달하게 되고
서버는 클라이언트가 요청보낸 세션ID를 가지고 세션 저장소에서 해당 로그인 정보를 찾아서
현재 요청보낸 사용자가 누구인지 알수 있게 된다.
이렇게 되면 사용자는 항상 세션 ID를 쿠키에 포함해서 서버에 전달하여 본인임을 인증하게 되어 항상 로그인을 할 필요가 없어진다.
--
Session ID를 탈취당하면?
--
세션 ID는 랜덤값으로 만들었기 때문에
탈취를 당한다고 해도 해당 세션ID에는 사용자의 정보가 없고 서버에 존재하기 때문에 괜찮다.
그러면 세션ID를 탈취하고 탈취범이 그대로 사용하게 된다면?
완벽하게 막을 수 있는지는 모르겠지만
세션의 만료시간을 짧게 만들어서 탈취한다고 해도 오래 사용하지 못하게 만들거나
해킹 의심이 되는 경우 세션메모리에서 세션을 강제 제거하도록 설계한다.
--
내가 생각하는 Session 정리 및 결론
--
클라이언트와 서버가 서로 세션ID만 가지고 로그인 정보를 판단하게 되어
세션 ID를 탈취당한다고 해도 해당 세션ID에는 로그인 정보가 없기 때문에 안전하다.
보안에 대해서는 세션 ID를 탈취를 하고 사용하는 부분에서만 신경을 써주면 될 것이다.
다만 세션은 사용자의 로그인 정보를 서버의 메모리(세션 저장소)에 저장을 하고 있어야 한다.
만약 서버가 잠시 꺼지게 되면 해당 로그인 정보를 저장하고 있는 메모리는 모두 지워지게 되어 사용자는 다시 로그인을 해줘야 하는 상황이 발생한다.
그리고 메모리는 상대적으로 용량이 적기 때문에 로그인 사용자가 많아지게 되면 메모리가 부족하게 된다.
그렇다고 로그인 정보를 메모리가 아닌 하드에 저장하게 되면 사용자가 매번 세션 ID를 보낼때마다 하드에서 찾아오는 것이 메모리에서 찾아오는 것보다 속도가 느려지게 된다.
결론적으로
Redis와 같이 캐시메모리를 빌려서 사용할 수 있는 환경이나
동시 로그인 접속자가 적은 환경일 경우에 사용하기 좋은 방법이라고 생각한다.
--
JWT 방식
--
- 사용자(클라이언트)가 서버에게 로그인 요청
- 서버는 로그인 정보를 가지고 Token을 생성하고 클라이언트에게 Token을 응답
- 이 후 사용자는 서버에게 요청할 때마다 쿠키 또는 헤더에 Token을 담아서 요청
- 서버는 Token을 해석하여 사용자 정보를 알 수 있게 된다.
사용자가 로그인을 하면 로그인 정보와 그 외의 부가적인 정보들을 가지고 암호화를 하여 Token을 생성하고
클라이언트에게 반환하게 된다.
이 후 사용자는 페이지 이동할 때마다 서버에게 Token을 함께 전달하게 되고
서버는 Token을 다시 복호화하여 그 안에 있는 정보들을 가지고 사용자가 누구인지 알 수 있게 된다.
여기서는 Token이 열쇠가 되는 것이다.
(열쇠 보다는 주민등록증(?)이 더 어울리는 것 같다.)
JWT 방식에서는 Session 방식과 다르게 서버에는 로그인에 대한 정보를 저장하고 있지 않다.
그래서 JWT는 Stateless(무상태성)이라고 부른다.
Stateless는 간단하게 서버가 클라이언트에 대해 정보를 가지고 있지 않는 상태를 말한다.
Token에 해당 사용자 정보가 담겨있으며 서버가 가지고 있는 것이 아니라 클라이언트가 가지고 있다.
그리고 서버는 Token을 받으면 복호화해서 확인할 수 있다.
이 또한 사용자는 항상 Token을 쿠키 또는 헤더에 포함해서 서버에 전달하여 본인임을 인증하게 되어 항상 로그인을 할 필요가 없어진다.
--
Token을 탈취당하면?
--
session 방식과 다르게 Token에는 로그인에 대한 정보가 들어있다.
Token은 암호화가 되어있기는 하지만 탈취자가 복호화를 하여 내용물을 볼 수 있기 때문에
Token안에는 로그인에 대한 정보가 들어있지만 탈취당해도 큰 타격이 없는 데이터드를 담아야 한다.
이러한 방식을 사용하면 탈취를 당해서 탈취자가 내용을 꺼내 본다고 해도 별 타격이 없을 것이다.
그러면 탈취자가 탈취한 Token을 그대로 사용을 한다면?
Token의 만료시간을 짧게 만들어서 탈취한다고 해도 오래 사용하지 못하게 만들수 있지만 완전히 막는 것은 어렵다.
물론 블랙리스트를 이용해서 해킹 의심이 되는 경우 Token을 블랙리스트에 올려서 해당 Token으로 요청이 오면
인증을 안하는 방법도 있기는 하다.
만약 Token을 탈취하고 복호화를 한 다음 내용을 변경하고 다시 암호화 후 사용을 한다면?
정보를 암호화하여 Token으로 만들 때 세 구조로 이루어져 있다.
- 헤더 (header)
- 정보 (payload)
- 서명 (signature)
여기서 내용이 변경된 것을 검증할 수 있는 곳이 서명 부분이다.
내용 변경이 된다면 Token 인증을 못하기 때문에 해당 부분은 그래도 안전하다고 생각된다.
--
내가 생각하는 JWT 정리 및 결론
--
우선 JWT의 가장 장점은 서버에서 Token을 관리하지 않는다는 점이다.
즉, 메모리에 데이터를 저장하지 않으니 데이터를 가져오거나하는 과정이 없어 속도가 빠를 것으로 보인다.
다만 서버에서 Token을 관리하지 않아 서버에서 Token에 대해 제어하기 어렵다.
그리고 Token 안에는 정보가 들어있기 때문에 Token에 넣을 정보도 보안을 생각하여 넣어야 하며
탈취 당했을 때의 대처 또한 대처하기 위해 다양한 로직을 작성해야할 것으로 보인다.
세션처럼 메모리에 데이터를 저장하고 있는 형태가 아니라서 서버에 대한 부화가 상대적으로 적을 것으로 보이며
속도를 신경써주기 위해 외부 캐시메모리를 돈 주고 사용하지 않아도 되는 것이 비용면에서는 좋아보인다.
다만 보안적으로는 세션보다 좋아보이지는 않다.
결론적으로
캐시메모리를 빌려서 사용하기 부담스럽거나 서버의 부화를 줄이고 싶거나
보안에 대해서 보강을 할 수 있거나 큰 신경을 쓰지 않다면 사용하기 좋아보인다.
--
Session과 JWT 중에서 무엇을 사용할까?
--
현재 쇼핑몰 프로젝트를 하고 있다.
금전적으로 아끼고 싶기도 하고 우선 가볍게 만들어 보고 싶어서 JWT를 사용하기로 결정했다.
JWT의 보안적인 문제도 보강하다 보면 JWT에 대해 조금 더 알 수 있을 것 같고
보강하는 과정 또한 재밌어 보이기 때문에 현재 프로젝트에서 JWT를 사용할 것이다.
--
'Self Q&A' 카테고리의 다른 글
[Spring Boot] API 요청 시 URI에 작성된 id가 본인이 맞는지 어떻게 검사할까? (0) | 2024.05.02 |
---|---|
[Spring Boot] 요청 받을 파라미터(@RequestParam)이 많으면? (0) | 2024.04.28 |
DTO를 깔끔하게 정리하는 방법이 없을까? (0) | 2024.04.25 |
JWT를 사용할 때 보안을 높이는 방법은 무엇이 있을까? (0) | 2024.04.19 |