2022. 9. 26. 14:17ㆍSW사관학교 정글_개발일지/미니 프로젝트
입소하자마자 우리에게 내려진 첫 과제는 3박 4일간 팀원들과 함께 사전 과제 때 학습한 것을 바탕으로 미니 프로젝트를 완성하는 것이었다. 주제는 자유였지만 필수적으로 포함되어야 하는 사항이 있었는데, 바로 로그인 기능과 Jinja 2 템플릿 엔진을 이용한 서버사이드 렌더링이다.
필수 포함 사항
- 로그인 기능
- Jinja2 템플릿 엔진을 이용한 서버사이드 렌더링
더 고민해볼 키워드
- Bootstrap을 대체할 CSS 라이브러리 사용하기 (Bulma, Tailwind 등)
- JWT 인증 방식으로 로그인을 구현하기 (쿠키/세션 대비 등장하게 된 배경은?)
웹페이지 개발에 대해서는 사전 과제 때 공부한 것 말고는 무지한 상태였기 때문에 이 중에 어떤 것도 구현해 본 적이 없었다. 팀원들과 회의 끝에 나는 로그인 기능 구현을 담당하게 되었다. 사실 어리석게도 로그인 구현을 다음과 같이 아주 만만하게 생각하고 있었다...
내가 상상한 회원가입 및 로그인 로직
회원가입
클라이언트: User가 회원 정보와 함께 ID, PW를 입력
서버: ID,PW 받아서 PW를 암호화하고 DB에 저장
로그인
클라이언트: User가 ID, PW를 입력
서버: ID,PW에서 받은 후 DB에서 확인해서 일치하는 User가 있다면 → 로그인 성공
엥 이게 로그인 맞지 않나?라고 생각했다 → 당신은 HTTP를 이해하지 못하고 있습니다
HTTP를 url 앞에 붙는 접두어 정도로 생각했던 나는 로그인은 이게 전부일 것이라고 생각했고... 구현을 위해서 공부를 하다 보니 로그인이라는 게 생각보다 심오하고 복잡한 문제라는 것을 알게 되었다.
로그인이 왜 복잡한 문제인지 알려면 우선 HTTP에 대한 이해가 필요하다.
HTTP (HyperText Transfer Protocol)
HTTP는 W3 상에서 정보를 주고받을 수 있는 프로토콜이다. 주로 HTML 문서를 주고받는 데에 쓰인다.
(... 중략 ...)
HTTP는 클라이언트와 서버 사이에 이루어지는 요청/응답(request/response) 프로토콜이다. 예를 들면, 클라이언트인 웹 브라우저가 HTTP를 통하여 서버로부터 웹페이지(HTML)나 그림 정보를 요청하면, 서버는 이 요청에 응답하여 필요한 정보를 해당 사용자에게 전달하게 된다. 이 정보가 모니터와 같은 출력 장치를 통해 사용자에게 나타나는 것이다.
HTTP를 통해 전달되는 자료는 http:로 시작하는 URL(인터넷 주소)로 조회할 수 있다.
출처: 위키피디아 (https://ko.wikipedia.org/wiki/HTTP)
쉽게 말하면, HTTP는 웹 상에서 클라이언트/서버 사이에 이루어지는 정보 교환에 대한 약속 또는 규칙이다. 클라이언트와 서버는 이 HTTP 아래에서 요청(Request)/응답(Response)을 통해 정보를 주고받는다.
HTTP가 가지고 있는 주요 특징은, 'Connectless'와 'Stateless'이다.
Connectless: 서버/클라이언트는 항상 연결되어있지 않다. 클라이언트가 서버에 요청하면 연결되고, 응답을 받으면 연결을 끊어버린다.
Stateless: Connectless하기 때문에, 서버는 클라이언트의 이전 상태를 알 수 없다. 즉, 클라이언트를 기억하지 못한다.
따라서, 내가 방금 ID/PW를 입력해서 서버로 요청을 보내고 서버가 "로그인 성공!"이라는 응답을 보냈다고 해도, 서버는 내가 로그인한 유저인지 기억하지 못한다. 다른 페이지를 방문할 때마다 무한 로그인을 해야하는 상황이 발생한다.
그러면, HTTP는 어떻게 이러한 문제를 극복하고 있을까?
여기서 '쿠키(Cookie)'와 '세션(Session)'이 등장한다.
쿠키(Cookie)
HTTP 쿠키(HTTP cookie)란 하이퍼 텍스트의 기록서(HTTP)의 일종으로서 인터넷사용자가 어떠한 웹사이트를 방문할 경우 사용자의 웹 브라우저를 통해 인터넷 사용자의 컴퓨터나 다른 기기에 설치되는 작은 기록 정보 파일을 일컫는다.
출처: 위키피디아 (https://ko.wikipedia.org/wiki/HTTP_%EC%BF%A0%ED%82%A4)
앞서 말했듯이, HTTP의 특성 때문에 클라이언트는 서버가 보내는 모든 요청을 별개로 취급한다. 기본적으로 클라이언트의 정보를 기억하지 않는다. 하지만 언어 설정 등 웹페이지를 이용할 때 유지가 되어야만 하는 상태 정보가 있을 수 있다. HTTP는 이러한 정보를 쿠키(Cookie)에 담아 브라우저에 저장할 수 있다.
쿠키의 작동 방식
1. 클라이언트의 요청
2. 서버가 쿠키를 굽는다🍪
3. 서버는 응답과 함께 쿠키를 돌려준다
4. 클라이언트는 받은 쿠키를 브라우저에 저장한다
5. 쿠키는 서버에 요청이 갈 때 자동으로 같이 전달된다.
상태 정보가 쿠키에 저장되고, 요청이 갈 때 자동으로 쿠키가 같이 가기 때문에 Stateless로 인한 HTTP의 약점이 극복될 수 있는 것이다. 쿠키에 로그인된 유저 정보를 저장한다면, 앞서 말한 무한 로그인 문제도 해결할 수 있을 것이다.
하지만, 일반적으로 쿠키에 로그인 정보를 저장하지는 않는다. 쿠키가 보안에 취약하다는 단점이 있기 때문이다. XSS, Sniffing에 의해 쉽게 탈취당할 수 있으므로 민감한 정보를 쿠키에 담기에는 불안하다. 쿠키에는 유출되어도 문제는 없지만 저장해두면 편리한 간단한 상태 정보를 담는 경우가 많다. (ex. 언어정보, '오늘 더 이상 이 창을 보지 않음', 자동 로그인 체크, 장바구니 등)
세션(Session)
세션이란, 일정 시간 동안 같은 사용자(브라우저)로부터 들어오는 일련의 요구들을 하나의 상태로 보고, 그 상태를 일정하게 유지시키는 기술이다. 여기서 일정 시간은 방문자가 웹 브라우저를 통해 웹 서버에 접속한 시간으로부터, 브라우저를 종료하여 연결을 끝내는 시점을 말한다. 즉 방문자가 웹 서버에 접속해 있는 상태를 하나의 단위로 보고, 이를 세션이라고 한다.
세션-쿠키 작동 방식
1. 클라이언트의 요청
2. 서버가 session-id를 session DB에 저장한다. 🪪
3. 서버는 응답과 함께 session-id를 쿠키에 담아 클라이언트에게 전달한다.
4. 클라이언트는 받은 쿠키를 브라우저에 저장한다
5. 재접속 시 쿠키를 통해 session-id가 서버에 전달된다.
6. 서버는 session DB에서 해당 session-id를 찾는다.
쿠키가 상태 정보를 로컬 PC에 저장하는 반면, 세션은 서버의 DB에 방문자의 상태를 저장한다. 유저 정보를 DB에 저장하기 때문에 도난/탈취의 위험이 적어 쿠키보다 안전하다는 장점이 있다. 그러나 세션을 유지하기 위해서는 서버에 세션 DB라는 별도의 database가 필요하므로, user가 늘어날수록 DB resource도 커지게 된다. Session DB로는 주로 redis라고 하는 open source DB를 사용한다고 한다.
쿠키 vs 세션?
구글링을 하다 보면 쿠키와 세션의 장단점을 비교해서 설명하는 글이 많아서, 쿠키와 세션을 둘 중에 양자택일을 해야 하는, 마치 대립되는 개념인것처럼 이해하는 경우가 많은 것 같다. (나도 처음에 그래서 세션이 좋다는거야 쿠키가 좋다는거야!? 했음)
하지만, 둘은 상호 보완되는 기술이라고 보는 것이 더 맞다. 로컬 PC에 상태를 저장하기 때문에 보안에 취약한 단점이 있는 쿠키를 보완하기 위해 세션을 함께 사용하는 것이다.
위의 그림처럼 세션-쿠키 방식을 사용하는 경우, 유저가 로그인했을 때 서버는 브라우저에게 session-id라는 key를 쿠키에 담아 전달해준다. 쿠키는 도메인 내 다른 사이트를 방문할 때 자동으로 전달되므로, 요청을 보내면서 쿠키와 함께 session-id가 같이 전달될 것이다. 그러면 서버는 받은 session-id를 session DB에서 찾고, "너가 아까 로그인한 걔구나!" 하고 알아보는 것이다.
세션-쿠키 방식으로 로그인 구현을 할 수 있으나, 정글에서는 JWT 인증 방식으로 로그인 구현하는 법을 더 고민해볼 키워드로 제안 주셔서, 이번 미니 프로젝트에서는 JWT를 이용해서 로그인을 구현하기로 하고 JWT 인증 방식에 대하여 더 공부해보았다. 다음 게시물에서는 Token과 JWT가 무엇인지, 세션/쿠키를 사용하는 것과 JWT를 사용하는 것에는 어떤 차이가 있는지 정리해보고, 우리 팀의 구현 방법을 소개해보려고 한다.
투비컨티뉴드