FrontEnd

[쿠키 2부]: 세션과 쿠키

guineaa 2024. 8. 6. 15:49

많은 사람들이 쿠키와 세션을 서로 대립하거나, 세션이 쿠키를 대체하는 기술로 오해하곤 한다.

사실 쿠키와 세션은 상호 보완을 하는 기술이라고 보는 것이 더 맞다.

 

1부에서는 서버가 브라우저에 쿠키를 어떻게 저장하고, 쿠키라는 기술의 한계에 대해서 알아보았다.

하지만 이러한 갖가지 단점에도 불구하고 쿠키는 여전히 웹에서 중요한 한 축을 담당하며 다양하게 사용되고 있다.

 

이번 포스팅에서는

웹 개발에서 쿠키를 사용할 수 밖에 없는 결정적인 이유와 세션 기반 사용자 인증에 대해서 알아본다.

 

HTTP 프로토콜의 특징

HTTP 프로토콜은 연결이 유지되지 않고 (connectionless), 상태가 없는 (stateless) 특성을 가지고 있다.

즉, 서버가 클라이언트의 요청에 응답하는 순간 HTTP 연결은 끊어지며, 클라이언트에서 새로운 요청을 해야지 다시 HTTP 연결이 맺어지게 된다. (하지만 브라우저는 응답된 데이터를 화면에 여전히 보여주고 있기 때문에 일반 사용자 입장에서는 브라우저와 서버간에 연결이 끊어졌다고 느끼지 않는다..)

 

이러한 HTTP 프로토콜의 특징은 웹에서 애플리케이션을 구현하는데 큰 걸림돌으로 작동하게 된다.

상태가 없다 라는 것은 각각 요청이 독립적으로 취급되어 여러 페이지에 걸쳐 흐름이 이어져야 하는 서비스를 구현하기 어려워 지기 때문이다.

 

간단한 웹사이트가 아닌 이상 하나의 브라우저로부터 순차적으로 들어오는 여러개의 요청이 동일한 사용자로부터 오는 것이라는 것을 알아햐 할것이다.

클라이언트와 연결이 유지되지 않는 상황에서 동시에 서버로 유입되는 수많은 요청이 각각 어느 사용자의 것인지 판단하는 것은 서버입장에서 매우 힘든일 일것이다.

 

여기서 쿠키의 지속성이 빛을 발휘한다. 바로 서버가 쿠키를 한 번 브라우저에 저장하면 브라우저는 해당 쿠키를 매 요청마다 계속해서 서버로 돌려 보낸다는 것이다.

 

다시 말해 서버가 브라우저에 쿠키 하나만 심어 놓으면 그 후로 브라우저는 성시랗게 매번 서버를 방문할 떄마다 해당 쿠키를 가져온다.

이러한 쿠키의 특성을 활용하면 서버는 각 요청이 어느 브라우저에서 오는 것인지 어렵지 않게 판단할 수 있다.

예를 들어 사용자가 서비스에 최초로 접속했을 때 서버가 브라우저에게 a=1 쿠키를 저장하라고 시키면 

HTTP 요청
GET /index.html HTTP/1.1
Host: www.test.com
HTTP 응답
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie:a=1

해당 브라우저는 사용자가 www.test.com  이라는 도메인에 머무는 한 /index.html을 방문하든

/about.html을 방문하든 /contact.html을 방문하든 매번 같은 쿠키를 돌려준다.

HTTP 요청
GET /index.html HTTP/1.1
Host: www.test.com
Cookie: a=1
HTTP 요청
GET /about.html HTTP/1.1
Host: www.test.com
Cookie: a=1
HTTP 요청
GET /contact.html HTTP/1.1
Host: www.test.com
Cookie: a=1

그러므로 서버 입장에서는 a=1 쿠키를 들고 오는 요청은 모두 이 브라우저로부터 오는것이라고

쉽게 알 수 있습니다. (물론 다른 브라우저에게는 a-1 대신에 a=2,a=3과같은 다른 쿠키를 응답해줘야한다)

 

부하 분산을 위한 쿠키 활용 (?!)

쿠키는 대규모 서비스에서 사용자 기반으로 부하 분산(load balancing)이 필요할 때 큰 역할을 할 수 있다.

수많은 사용자로부터 동시에 들어오는 요청을 처리하려면 일반적으로 여러 대의 서버를 운영할 수 밖에 없는데,

이런 경우 서버 앞 단에 로드 밸런서(load balancer)를 두고 부하가 여러 대의 서버로 분산될 수 있도록 인프라를 구성한다.

이러한 환경에서 로드 밸런서가 서비스로 들어오는 요청을 순차적으로 round-robin 또는 랜덤하게 서버에 배정하면 어떻게 될까? 만약에 사용자의 세션 정보가 각 서버 단위로 관리되고 있다면 사용자를 로그인된 상태로 유지하는것이 매우 어려울 것이다.

 

즉, 1번 서버에서 세션을 생성한 사용자가 다음 요청 때 2번 서버에 붙게 된다면,

서비스는 이 사용자를 로그인된 사용자로 인식할 수 없을 것이다.

왜냐하면 2번 서버에는 해당 사용자의 세션 정보가 존재하지 않을 것 이기 때문이다.

이 경우 쿠키를 활용하면 어렵지 않게 사용자를 고려하여 부하 분산을 할 수 있다.

예를 들어, 사용자가 서비스에 최초로 접속했을 때 그 요청을 처리한 서버가 자신의 식별자를 쿠키로 저장하라고 브라우저에 시키면 

HTTP 요청
GET /index.html HTTP/1.1
Host: www.test.com
HTTP 응답
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: serverId=1

해당 브라우저는 사용자가 해당 사이트의 어느 페이지를 방문하든 serverId=1 쿠키를 돌려 보낼 것이다.

 

HTTP 요청
GET /index.html HTTP/1.1
Host: www.test.com
Cookie: serverId=1

HTTP 요청
GET /about.html HTTP/1.1
Host: www.test.com
Cookie: serverId=1

HTTP 요청
GET /contact.html HTTP/1.1
Host: www.test.com
Cookie: serverId=1

그럼 로드 밸런서(load balancer)는 이 식별자를 보고 이 브라우저에서 오는 요청을 항상 동일한 1번 서버로 보내줄 수 있을 것이다. 참고로 이렇게 사용자 기반 부하 분산은 주로 소규모의 서비스에서 볼 수 있으며, 대규모 서비스에서는 서버간에 공유가 가능한 별도의 데이터 베이스에 세션 정보를 관리하는 경우가 많다.

 

세션 기반 사용자 인증

쿠키의 최대 단점?? 쿠키는 브라우저에 저장하기 때문에 유실/변조/도난되기 쉽다

쿠키 대비 세션의 장점?? 세션은 서버 측에서 관리 되기 때문에 위와 같은 위험이 적다.

그러면 도대체 서버 측에 생성된 수많은 세션이 어떤 사용자의 것인지 어떻게 알 수 있을까??

 

예를들어, 잠시 보안은 잊어버리고 사용자의 인증 정보를 쿠키로 저장한다고 가정하자

사용자가 브라우저에서 로그인 페이지를 열고 인증 정보를 입력한 후 서버에 전송한다.

HTTP 요청
POST /login HTTP/1.1
Host: www.test.com
Content-Type: application/x-www-form-urlencoded
Content-Length:27

username=test&password=1234

그럼 서버는 사용자 DB를 조회해서 인증 정보를 검증하고 응답할 때

인증 정보를 쿠키로 브라우저에 보낼것이다.

HTTP 응답
HTTP/1.1 302 Found
Content-Type:text/html
Location:https://www.test.com/
Set-Cookie: username=test
Set-Cookie: password=1234

그러면 브라우저는 매번 요청을 보낼 때마다 이 인증 정보가 담긴 쿠키를 서버로 돌려 보낼 것이다.

 

HTTP 요청
GET /HTTP/1.1
Host: www.test.com
Cookie: username=test; password=1234

그럼 서버에서 사용자 인증을 위해서 할 일은 이 쿠키로 넘어온 인증 정보가 사용자 DB에 존재하는지 확인하는것 밖에 없다.

 

이번에는 사용자가 입력한 인증 정보를 세션으로 저장하는 시나리오도 생각해보자.

동일하게 사용자가 브라우저에서 로그인 페이지를 열고 인증 정보를 입력 후 전송한다.

HTTP 요청
POST /login HTTP/1.1
Host: www.test.com
Content-Length:27
Content-Type:application/x-www-form-urlencoded

username=test&password=1234

서버는 사용자 DB를 조회해서 인증 정보를 검증하고 서버에 세션을 생성한다.

이제부터는 사용자는 브라우저로 웹사이트의 이페이지 저페이지를 방문할텐데 어떻게 로그인 상태로 유지시킬까!

이때 등장하는 구원 투수가 쿠키이다.

 

서버에서 세션을 생성하면 그 세션을 식별할 수 있는 식별자를 얻을 수 있다.

보통 이것을 세션 아이디라고 부른다. 이 세션 아이디를 쿠키로 브라우저에 응답해주면 어떻게 될까?

HTTP 응답
HTTP/1.1 302 Found
Content-Type: text/html
Location: https://www.test.com/
Set-Cookie: sessionId=a2dd774336e2

그러면 브라우저는 매번 요청을 보낼 때마다 이 세션 아이디가 담긴 쿠키를 서버로 돌려 보낼 것이다.

HTTP 요청
GET /HTTP/1.1
Host: www.test.com
Cookie: sessionId=a2dd774e36e2

이제 서버에서는 이 세션 아이디에 해당하는 세션이 존재하는지만 확인해주면 된다.

위 예시는 어디까지나 전반적인 개념을 위해 단순화 되었으며 실전에서는 세션 아이디를 담은 쿠키에 유효 기간도 설정하고 적용 범위도 제한하고 보안 속성도 추가한다.

적어도 브라우저에 인증 정보를 저장하지 않았으니 클라이언트 컴퓨터가 털리더라도 인증 정보가 유출될 일은 없다.

 

 

쿠키 2부: 세션은 쿠키가 필요해~ | Engineering Blog by Dale Seo