우리는 웹사이트를 만들 때 로그인 기능을 구현하는 일이 많습니다. 프로젝트에서도 로그인 기능은 다룰려고 하는 추세입니다. 그러나 로그인 자체가 보안적으로 굉장하게 신경을 써야 하고, 이런 상황 저런 상황을 고려해야 합니다.
해당 글은 필자가 부족한 지식으로 작성한 글임을 알립니다. 이상한 내용이 있다면 댓글남겨주시길 바랍니다.
로그인 유지가 필요한 이유
메인 페이지에서 로그인 후에 다른 페이지에 들어갈 때 로그인을 새로 해야 한다면, 사용자 경험이 좋게 느껴질 수 있을까요? 저라면 그런 사이트는 이용하고 싶지 않을 것 같습니다😭😭
웹 브라우저와 웹 서버가 데이터를 주고 받을 때 HTTP(HyperText Transfer Protocol) 통신을 이용합니다. HTTP는 서버의 부담을 줄이기 위해 비연결성(Connectionless)과 비상태성(Stateless) 특징을 가집니다. 서버가 클라이언트 요청에 대한 응답을 하면 연결이 끊어지고 클라이언트가 다시 요청하면 서버는 이전 요청에 대한 정보를 지니고 있지 않습니다.
이로 인해 같은 사용자가 여러 번 요청하더라도 매번 새로운 사용자로 인식하게 됩니다. 하지만 로그인이나 장바구니처럼 클라이언트의 상태가 유지되어야 하는 상황이 생깁니다.
어느 행동을 할 때마다 로그인을 새로하지 않기 위해서 로그인을 유지시키는 방향으로 가야합니다. 로그인을 유지시키기 위해서는 크게 쿠키 방법과 세션 방법으로 나눌 수 있습니다.
쿠키를 사용해보자 🍪
쿠키는 클라이언트에 저장되는 key와 value로 구성된 데이터입니다. 쿠키는 정보들을 웹 브라우저에 저장하고 사용자가 요청하면 해당 정보를 함께 보내서 서버가 사용자를 식별할 수 있게 해줍니다.
중요한 부분은 클라이언트에 저장이 된다는 점입니다. 클라이언트에 저장이 된다라는 사실은 여러 상황으로 직결될 수 있습니다.
1. 서버에서 따로 저장을 하지 않기 때문에 서버 과부화가 일어나지 않는다.
2. 누군가가 쿠키에 담긴 나의 토큰 정보를 빼앗긴다면 나인척 할 수 있다.
쿠키에서의 로그인 과정은요?!
1. 클라이언트가 로그인을 시도합니다.
2. 로그인을 성공했을 경우, 서버는 토큰을 생성해서 클라이언트에 전달합니다.
3. 클라이언트는 쿠키에 토큰을 저장합니다.
4. 해당 사이트에서 특정 행동을 할 때마다 클라이언트는 쿠키에서 토큰을 가져와서 서버로 보냅니다.
5. 서버에서는 토큰이 유효한지 판단을 하며 클라이언트와 통신합니다.
보안적으로 봤을 때, 토큰이 탈취 될 가능성이 있어서 쿠키만 사용한다는 것은 좋은 생각이 아닙니다.
세션을 사용해보자 📔
세션은 서버에 저장되는 정보입니다. 세션은 비밀번호와 같은 인증 정보를 쿠키에 저장하지 않고 서버에 저장하며 대신 쿠키에는 사용자 식별자인 session-id를 저장합니다. 이처럼 세션도 쿠키를 이용하지만 추정 불가능한 session-id를 주고받기 때문에 보안상 안전합니다.
따라서 노출되면 안 되는 중요한 정보는 세션을 이용하여 저장합니다.
여기서 헷갈리면 안되는게, 세션과 세션 스토리지는 다르니까 주의합시다.
1. 세션은 서버에 저장되다 보니까, 너무 많이 담기면 서버 과부화가 일어날 가능성이 생깁니다.
2. 서버에서 사용되다 보니까, 쿠키보다는 탈취되는 과정이 어렵습니다.
세션에서 로그인 과정은요?!
1. 클라이언트가 로그인을 시도합니다.
2. 로그인에 성공했을 경우, 서버는 클라이언트 고유 session-id를 생성하고 서버에 저장합니다.
3. 서버는 클라이언트에게 session-id를 전달합니다.
4. 클라이언트는 session-id를 가져오면서 서버와 통신합니다.
5. session-id가 유효한지 확인하며 클라이언트와 소통합니다.
세션만 사용하는 것도, 과부화가 일어날 수 있고 좋은 점만 있는 것은 아닙니다.
서버 메모리에 정보를 따로 저장해야 한다는 점을 보완하여 토큰 방식인 JWT가 등장하게 됩니다.
JWT를 사용해보자🍪🍪
JWT란 JSON Web Token의 약자로 인증에 필요한 정보들을 암호화시킨 토큰을 의미합니다. JWT 기반 인증은 세션 방식과 유사하게 JWT를 HTTP 헤더에 실어 서버가 클라이언트를 식별합니다. JWT는 사용자 인증에 필요한 모든 정보를 토큰 자체에 담고 있어서 세션 방식과 달리 서버에 별도 저장소가 필요하지 않습니다.
JWT는 쿠키를 이용하면서 생겨났던 기존의 보안적인 문제를 해결하려고 노력했습니다. 결과적으로는 accessToken, refreshToken을 사용하게 되었습니다. 각 토큰들은 만료시간이 있습니다. 만료시간이 된다면 토큰은 유효하지 않은 토큰이 됩니다. 상대적으로 accessToken은 짧게, refreshToken은 길게 잡습니다.
유저가 특정 행동을 할 때에는 accessToken으로 식별합니다. refreshToken은 accessToken이 만료되었을 경우 accessToken을 재발급해줍니다. 다시 말하면, refreshToken을 통해서 다시 로그인하는 과정이라고 생각하면 됩니다.
JWT에서 로그인 과정은요?!
1. 클라이언트가 로그인을 시도합니다.
2. 서버에서 사용자의 고유한 ID와 다른 인증 정보들을 JWT에 Payload에 담습니다. 이때 두 토큰의 유효기간을 설정합니다.
3. 서버가 갖고 있는 비밀 키를 이용해서, Token을 만들어냅니다.
4. 사용자는 서버로부터 토큰을 받아 저장하고 해당 토큰을 보내면서 서버와 통신합니다.
5. accessToken은 기간이 지나 만료가 되었지만, refreshToken의 기간이 지나지 않았다면 자동으로 accessToken을 재발급받습니다.
6. refreshToken까지 기간이 만료되었다면 새로운 로그인이 필요합니다.
여기서 다시 생각해볼 수 있는 문제는, 토큰이 탈취되면 어떻게 되는 지에 대한 문제입니다. accessToken을 탈취 당했다면 일정시간동안은 그 유저인척 할 수 있습니다. 대신, 시간이 만료된다면 더이상 유저인척 할 수 없습니다. 완벽한 보안 방법은 아니지만, accessToken의 만료 기간을 짧게 잡는다면 괜찮을 수도 있습니다.
그렇다면 JWT만 사용하는 것이 좋나요?
제 생각은 아니라고 말할 수 있습니다. 저는 JWT, 세션 두 가지의 방법을 같이 사용하면 좋다고 생각합니다. 그 이유는 다음과 같습니다.
먼저 사용자가 얼마나 있을 지 예측을 해야 합니다. 세션은 상대적으로 서버에 부담을 주기 때문에 동시 접속 사용자 수에 맞추어서 적절한 설계를 할 수 있어야 합니다.
1. 로그인 유지와 같은 간단한 정보는 쿠키를 통해서 서버의 부담을 덜어냅니다.
2. 보안적으로 숨겨야 하는 부분이 생긴다면 세션을 사용합니다.
3. 강제 로그아웃 같은 기능을 고려해야 하기 때문에(은행에서 사용하듯이) 서버에서 유저의 로그인 상태를 변경하려면 세션을 사용해야 합니다.
서버를 분리하면서 세션의 역할을 하는 데이터베이스를 만든다면은 보안적으로 좋을 수 있을 것이라고 생각합니다.
참고자료
https://velog.io/@yaytomato/프론트에서-안전하게-로그인-처리하기
'Web > techTalk' 카테고리의 다른 글
Virtual DOM 을 왜 사용하나요? (Feat. React reconciliation) (0) | 2022.07.05 |
---|---|
[css] z-index, stacking context(쌓임 맥락)에 대해서 알고있나요? (0) | 2022.03.18 |
[React] Atomic, Container Presenter 어떤 디자인패턴을 써야할까? (0) | 2022.03.18 |
[Test Code] Unit Test, Integration Test, Acceptance Test (0) | 2022.03.06 |