Stateful과 Stateless
•
Stateful(상태유지)
◦
상태 유지는 클라이언트-서버 관계에서 서버가 클라이언트의 상태를 보존하는 것을 의미한다.
◦
대표적인 예로 로그인이 있는데, 한번 로그인 이후 페이지를 옮길 때마다 새로 로그인 할 필요가 없는 이유가 서버에서 클라이언트 상태를 알고 있기 때문에 가능한 것이다.
◦
TCP의 3-way handshaking 방식도 SYN → SYN + ACK → ACK 과정동안 세션을 유지하여 세션의 상태에 따라 서버의 응답이 달라지는 stateful한 프로토콜이다.
◦
stateful 방식은 서버가 멈추거나 다른 이유로 사용하지 못할 때 다른 서버를 통해 서비스를 지원하게 되는 경우, 기존의 서버에서 유지하고 있던 상태값들을 전부 잃어 새로 상태값들을 저장해야한다는 문제가 있다.
◦
또한 클라이언트에서의 요청이 많이 들어올 경우 서버에서 각각 상태값들을 저장하고 있어야하기 때문에 부하가 많이 들고 용량에 한계가 있다는 단점이 있다.
•
Stateless(무상태)
◦
무상태는 클라이언트-서버 관계에서 서버가 클라이언트의 상태를 보존하지 않는 것을 의미한다.
◦
클라이언트-서버 간의 통신에 필요한 모든 상태 정보들을 클라이언트에서 가지고 있다가 서버와 통신할 때 쿠키로 같이 보내는 것으로, 서버는 단순히 요청이 오면 응답을 보내는 역할만 수행한다.
◦
상태를 보관하지 않기 때문에 서버 1에 문제가 생겨도 서버 2에서 이어 응답하는데 문제가 없다. 같은 이유로 서버 확장이 용이하다는 장점이 있다.
◦
다만 클라이언트에서 모든 정보를 들고 있기 때문에 정보 탈취에 취약하고, 네트워크에 부하가 많이 발생한다는 단점이 있다.
•
서버에 부하가 줄어든다는 측면에서 stateless 방식이 좋지만, 로그인 유지와 같이 개인 정보가 포함되는 경우 stateful하게 구현해야한다. 이런 이유로 로그인 정보들을 암호화하여 클라이언트에서 들고 있다가 서버에 넘겨주는 토큰 인증 방식이 사용된다.
쿠키
•
웹 브라우저에서 쿠키(Cookie)란 서버와 클라이언트 간에 통신할 때 전송하는 작은 데이터 조각으로, key=value 형식의 문자열 데이터 묶음이다. 브라우저에서는 이 문자열 데이터를 저장해두었다가 동일한 서버에 재요청 시 같이 보낼 수 있다.
•
로그인과 같은 서버 간의 일시적인 연결에서 세션 관리에 사용되고, 웹사이트에 대한 사용자 선호도나 테마와 같은 설정값을 개인화하거나 사용자의 행동을 기록하고 분석하여 광고를 띄우는 트래킹의 용도로도 사용된다.
•
쿠키는 클라이언트 측에서 관리 되기 때문에 악용될 우려가 있고, 보안에 취약하여 정보가 탈취당할 위험성이 존재한다. 그렇기 때문에 보안에 민감한 비밀번호나 주민번호와 같은 개인 정보는 사용하면 안된다. 또한 쿠키의 용량이 커지면 네트워크의 트래픽에 부하가 증가한다.
•
쿠키 생명 주기
◦
expires와 max-age를 통해 만료일을 설정할 수 있다.
◦
예시) expires=Sate, 26-Dec-2020 04:39:21 GMT, max-age=3600
◦
만료 날짜를 생략하면 쿠키는 브라우저 종료 시 까지만 유지되는데 이를 세션 쿠키라 부른다.
◦
만료 날짜를 입력하면 해당 날짜 혹은 해당 시간 동안 유지되는데 이를 영속 쿠키라 부른다.
•
쿠키 경로(Path)
◦
쿠키에 경로를 설정하면, 해당 페이지 경로와 그 하위 경로에서만 쿠키 사용이 가능하다.
◦
예시) path=/home 지정 시 /home/level1 → 접근 가능, /home/level2 → 접근 가능, /hello → 접근 불가
•
쿠키 도메인(Domain)
◦
쿠키에 도메인을 설정하면 해당 도메인과 서브 도메인의 페이지에서만 쿠키 사용이 가능하다.
◦
예시) domain=example.org 지정 시 example.org → 접근 가능, www.example.org → 접근 가능, exam.org → 접근 불가
◦
사용자가 방문하고 있는 도메인에서 발행한 쿠키를 퍼스트 파티 쿠키(First-Party Cookie)라 부르고, 타 도메인에서 발행된 쿠키를 서드 파티 쿠키(Third-party Cookie)라 부른다.
서드 파티 쿠키
서드 파티 쿠키는 주로 타킷 마케팅 광고 목적으로 사용된다. 특정 사이트를 자주 방문하게 되면 쿠키가 저장되고 해당 쿠키를 구글 애드센스가 이 서드 파티 쿠키를 읽어 다른 사이트에서 배너 광고로 해당 제품이 나타난다.
•
쿠키 보안
◦
Secure
▪
쿠키에 Secure가 활성화 되면 https에서만 쿠키 정보를 전달 가능하고, 미적용 시 http와 https를 구분하지 않는다.
◦
HttpOnly
▪
JavaScript에서 쿠키를 사용해 접근하는 것을 제한하여, XSS 공격을 방지할 수 있다.
◦
SameSite
▪
서드 파티 쿠키의 보안적 문제를 해결하기 위해 만들어진 기술로, 요청 도메인과 쿠키 정보 내의 도메인이 달라 크로스 사이트(Cross-site)로 전송하는 요청에 대해 제한을 두어 XSRF 공격과 CSRF 공격을 방지할 수 있다.
쿠키 인증
•
쿠키 인증은 쿠키를 통해서 클라이언트에 저장하고 싶은 인증 정보를 저장하고, 서버에 해당 쿠키를 매번 담아 보내서 서버에서 해당 요청의 클라이언트를 식별하는 방식이다.
•
요청 시 쿠키의 값을 그대로 보내기 때문에 유출 및 조작 당할 위험이 커 보안에 아주 취약하다는 단점이 있다.
•
쿠키에는 용량 제한이 있기 때문에 많은 정보를 담을 수 없고, 쿠키의 용량이 커질수록 네트워크에 부하가 심해진다.
세션(Session) 인증
•
쿠키의 보안적인 이슈 때문에 비밀번호나 클라이언트의 민감한 인증 정보를 브라우저가 아닌 서버 측에 저장하고 관리하는 방식이다.
•
쿠키를 포함한 요청이 외부에 노출되더라도 세션 ID 자체는 유의미한 개인정보를 가지고 있지 않기 때문에 문제가 되지 않는다. 하지만 세션 ID 자체를 탈취하여 클라이언트인 척 위장할 수 있다는 한계가 있다.
•
서버에 데이터를 저장하는 세션 저장소를 사용하므로 요청이 많아지면 서버에 부하가 심해지고, 요청 시마다 세션 정보를 조회하는 과정이 발생해 오버헤드가 발생한다.
•
stateful한 특징을 가지고 있어 서버 확장성이 좋지 않다.
토큰(Token) 인증
•
클라이언트가 서버에 접속을 하면 서버에서 해당 클라이언트에 인증되었다는 의미로 토큰을 부여하는 방식이다.
•
클라이언트에서 발급받은 토큰을 서버에 요청할 때 헤더에 담아서 보내면, 서버에서 제공한 토큰과 일치 여부를 확인하여 인증 과정을 처리한다.
•
토큰을 클라이언트에 저장하기 때문에 서버의 부하를 덜 수 있고, 토큰 자체에 데이터가 들어있기 때문에 서버는 위조 판별만 하면 된다.
•
쿠키나 세션과 다르게 토큰 자체의 데이터가 길기 때문에 인증 요청이 많아질수록 네트워크 부하가 심해진다는 단점이 있다.
•
토큰의 Payload 자체는 암호화되지 않기 때문에 유저의 중요한 정보를 담을 수 없고, 토큰을 탈취당하면 대처하기 어려워 사용 기간을 제한하는 방식으로 사용되어야 한다.
•
stateless한 특징을 가지고 있어 서버 확장성이 좋아질 수 있다.
JWT(JSON Web Token)
•
JWT는 인증에 필요한 정보들을 암호화시킨 JSON 토큰을 의미한다. JWT 토큰을 HTTP 헤더에 담아 서버가 클라이언트를 식별하는 방식이다.
•
JSON 데이터를 Base64 URL-safe Encode 방식으로 인코딩하여 직렬화한 데이터가 JWT 토큰이며, 토큰 내부에 위변조 방지를 위한 개인키를 통한 전자서명이 들어있다.
Base64 URL-safe Encode는 일반적인 Base64 Encode에서 URL 오류없이 사용할 수 있도록 +, /를 각각 -, _로 표현한 것이다.
•
JWT 구조
◦
JWT는 .을 기준으로 나누어지는 Header, Payload, Signature인 문자열의 조합이다.
◦
Header
▪
Header에는 JWT에서 사용할 타입과 알고리즘의 종류가 담겨있다.
▪
alg : 서명 암호화 알고리즘(ex: HMAC SHA256, RSA 등)
▪
typ : 토큰 유형
◦
Payload
▪
Payload에는 서버에서 첨부한 사용자 권한 정보와 데이터가 담겨있다.
▪
정해진 데이터 타입은 없지만 Registered claims, Public claims, Private claims로 나뉜다.
▪
Registered claims : 미리 정의된 클레임
▪
Public claims : 사용자가 정의할 수 있는 클레임(공개용)
▪
Private claims : 사용자가 정의할 수 있는 클레임(비공개용)
◦
Signature
▪
Signature는 개인키로 서명한 전자 서명이 담겨있다.
▪
헤더에 정의한 알고리즘을 사용하여 헤더와 페이로드를 인코딩한 문자열이다.
▪
Header와 Payload는 단순히 인코딩된 값으로 제 3자가 복호화 및 조작할 수 있지만, Signature는 서버 측의 개인 키가 유출되지 않는 이상 복호화 할 수 없다. 때문에 Signature로 토큰의 위변조 여부를 확인할 수 있다.
•
JWT 장점
◦
Signature를 통해 데이터의 위변조를 막을 수 있다.
◦
토큰 방식이기 때문에 별도의 저장소가 필요없어 서버의 부하가 적다.
◦
토큰 기반으로 다른 로그인 시스템에 접근 및 권한 공유가 가능하다.
◦
모바일 어플리케이션 환경에서도 동작 가능하다.(세션은 모바일 환경에서 불가능)
•
JWT 단점
◦
토큰 자체에 정보를 담고 있고 payload 자체는 암호화 된 것이 아니기 때문에 중간에 탈취하면 정보가 노출될 수 있다. 때문에 중요한 정보를 담을 수 없다.
◦
토큰에 정보를 저장하므로 정보가 많아질수록 토큰의 길이가 늘어나 네트워크에 부하를 줄 수 있다.
◦
토큰은 클라이언트에서 관리하는데, 토큰 자체를 탈취 당하면 대처가 어려워 토큰 제한 시간을 두어야 한다.
Access Token & Refresh Token
•
JWT를 Access Token으로 사용하는 인증 방식의 문제는 제 3자에게 탈취당할 경우 보안에 취약해진다는 점이다.
•
이를 극복하기 위해 토큰에 유효 시간을 부여하여 대응하는데, 유효 시간이 짧다면 자주 재인증이 필요하다는 단점이 있고 길다면 토큰을 탈취 당했을 경우에 보안에 취약해진다.
•
이런 문제점들을 해결하기 위한 방안이 Access Token이 만료되었을 경우 토큰 재발급에 관여하는 Refresh Token이다. Refresh Token은 긴 유효 시간을 가지고 Access Token이 만료되었을 경우 같이 보내진 Refresh Token과 DB에 저장해둔 Refresh Token과 비교하여 일치하면 다시 Access Token을 발급해준다.
•
토큰 발급 case들
◦
access token, refresh token 모두 만료된 경우 → 다시 로그인하여 둘 다 새로 발급
◦
access token 만료, refresh token 유효 → refresh token을 검증하여 access token 재발급
◦
access token 유효, refresh token 만료 → access token을 검증하여 refresh token 재발급
◦
access token 유효, refresh token 유효 → 정상 처리
•
로그아웃하면 두 토큰을 모두 만료시킨다.