HTTP는 인터넷 상에서 데이터를 주고 받기 위한 서버-클라이언트 모델을 따르는 프로토콜임.
클라이언트가 서버에게 요청을 보내면, 서버는 응답을 보내줌으로써 데이터를 교환합니다.
HTTP는 비연결성(Connectionless), 무상태성(Stateless)의 특징을 가지고 있습니다.
이 말은 곧 요청에 대한 응답을 처리 완료하게 되면, 연결을 끊어버림을 뜻합니다.
따라서 클라이언트에 대한 이전의 상태 정보 및 통신 상태가 남아있지 않게 됩니다.
HttpOnly
속성을 사용하여 보안을 강화할 수 있습니다.(4KB 이하)
를 저장하는 데 사용됩니다. 반면 웹 스토리지는 최대 5MB의 데이터를 저장할 수 있다.성능, 신속성, 오프라인 기능, 사용자 로그인 상태 유지 등
일반적으로 로컬 저장소를 웹에서 사용할 경우 가장 많이 사용되는 방법은 쿠키, 로컬 스토리지이다.
쿠키와 로컬 스토리지는 각각 다른 목적을 가지고 있기 때문에 적합한 방법을 채택해야한다.
쿠키는 서버측과 클라이언트 측 양쪽에서 쿠키 데이터를 사용하는 api가 존재한다.
로컬 스토리지는 로컬 환경에서만 컨트롤 할 수 있다.
예시로 쿠키 데이터의 쓰임이 웹과 서버 양쪽에서 다 쓰이고, 서버쪽에서 활용이 높다면 쿠키값을 사용하는 것이 효율적일 것이다.
광고 7일 동안 보지않기 같은 기능은 쿠키로 구현한다고 한다.
반면 로컬 스토리지에는 유효 기간과 관련된 메소드가 없기 때문에 별도로 코드를 작성해줘야 한다.
LocalStorage
SesstionStorage
보통 세션의 종료는 "브라우저의 종료"를 뜻합니다.
하지만 세션 스토리지에서 의미하는 세션은 가장 작은 단위인 "탭"단위를 의미합니다.
"탭"마다 세션 스토리지는 따로 배정되며 서로의 영역을 공유하지 않습니다. 서로 값을 침범할 수 없음.
(독립적)
따라서 쿠키는 도메인이 같으면 항상 쿠키를 보내는 툭징이 있는데, 세션 스토리지는 각자의 탭 안에서만 의미가 있기 때문에 보안적으로 더 좋다.
쿠키
HttpOnly
속성으로 XSS 공격을 방어할 수 있다.데이터의 일관성을 유지해야한다. 두 저장소에 동일한 정보가 일치하도록 조치해야한다.
인증
사용자가 로그인을 시도하면, 서버는 사용자의 신원을 확인
유효한 경우 - 엑세스 토큰, 리프레시 토큰을 발급
일반적으로 엑세스 토큰은 짧은 유효기간을 가지고, 리프레시 토큰은 더 긴 기간 유효하다.
예시 ) 유효기간 : 엑세스 토큰 30분 || 리프레쉬 토큰 1달
엑세스 토큰 사용
클라이언트는 엑세스 토큰을 사용하여 보호된 엔드포인트에 요청을 보낸다.
이 토큰은 서버에 의해 검증. 사용자의 권한을 확인하고 허용된 작업을 가능하게 한다.
보호된 엔드 포인트
서버에서 보호된(인증이 필요한) API 또는 리소스에 액세스하려고 클라이언트가 서버에 요청을 보내는 것을 의미
엑세스 토큰 갱신
엑세스 토큰이 만료되기 전에 클라이언트는 리프레시 토큰을 사용하여 새로운 엑세스 토큰을 받을 수 있다.
이를 통해 사용자는 로그인 상태를 유지할 수 있다.
리프레시 토큰 사용
리프레시 토큰을 사용하여 새로운 엑세스 토큰을 받는 동안, 서버는 클라이언트가 여전히 유효한 사용자인지 확인한다.
만약 리프레시 토큰이 만료되었다면, 사용자는 다시 로그인해야 한다.
보통은 액세스 토큰이 갱신될 때 리프레시 토큰도 함께 갱신하는 방식을 채택한다.
로그아웃
사용자가 로그아웃 하거나 세션이 종료된 경우, 클라이언트는 로컬에서 저장된 토큰을 삭제한다.
모바일 웹에서도 웹 스토리지와 쿠키를 사용할 수 있다.
웹 스토리지는 자바스크립트 API 중 하나이기 때문에 브라우저가 실행되는 모든 환경에서 사용할 수 있다.
클라이언트에서 토큰 검증이 이루어지면 절대 안된다. 검증은 무조건 서버측에서 이루어져야 한다.
클라이언트 측에서는 받은 정보를 서버로만 보내주고, 받는 행위만 이루어져야한다.
토큰에 유저정보를 같이 넣어서 보내면 안됩니다!클라이언트는 보안에 관련된 그 어떠한 것들도 판단하거나 처리하면 안된다.
오로지 서버로 전달만 합니다.
즉, 서버에서만 토큰을 까봐야합니다. 즉, 클라이언트 측에서 토큰을 먼저 까서 서버로 보내면 안된다.
토큰 인증 및 에러 처리, 로딩 상태 관리, 요청/응답 로깅
하는 데에 인터셉터를 사용할 수 있다.
인터셉터
인터셉터를 적용하는 예시
Json Web Token
웹기술 표준
rfc - request for comments
헤더와 페이로드는 아무나 까서 볼 수 있음.
시크릿 키 노출
헤더와 페이로드는 이미 공개되어 있고, 시크릿 키는 암호화되어 있는데 이것이 노출된다면 무한하게 토큰을 찍어낼 수 있는 경우가 생김
즉, 모든 정보가 노출될 수 있는 위험이 있음.
헤더와 페이로드는 아무나 까서 볼 수 있음.
데이터 복호화로 인한 정보 유출
토큰 자체가 스스로의 유효성을 검증하는 완결성을 가진다.
클라이언트에서는 토큰 탈취를 주의해야합니다.
Q. 페이로드 까서 보는건 어차피 누구나 할 수 있는 건데도 그 페이로드 까서 사용하는 코드를 프론트엔드에서 직접 수행하고 있으면 안좋다는 건가요?
A. 그렇다. 그 이유는 클라이언트에서 페이로드를 디코딩해서 사용하는 순간, 클라이언트 사이드의 자바스크립트 코드 내에 페이로드를 디코딩하는 방법과, 그 안에서 유의미한 정보를 추출하는 방법을 알려주는 셈이 되기 때문입니다. 가급적이면 보안관련 알고리즘은 숨기는 것이 좋다.
따라서 유의미한 정보를 추출하는 코드들은 서버에서 작동하는 것이 보안상 가장 좋다.
추가적으로 페이로드를 까서 클라이언트 기능에 이용하는 것은 백엔드의 암호화 로직에 프론트엔드 기능의 의존성이 걸린다는 이야기이기도 하다.
백엔드에서는 보안 방식을 변경하고자 하는 것인데, 클라이언트에서 갑자기 유저 이름을 보여주는 기능에 문제가 생기는 일이 발생할 수 있다.
토큰 뿐 아니라 어떤 기능들을 개발할 때, 가능하면 지금 있는 것으로 어떻게든 구현할 수 있는 것보다 그 기능들이 서로 얽히지 않도록 하는 것을 권장한다.
리프레시 토큰의 유효성 검증을 유저 정보 조회 API에 달아서 사용할 수 있다.
토큰이 유효하다면 / 로그인에 성공했다면 유저정보+토큰을 내려주는 식으로.
근데 이건 백오피스성 서비스고, 실제 서비스면 이마저도 분리하는게 좋을것 같습니다.
토큰을 스토리지에 저장한다면 리프레시토큰만 로컬스토리지에 저장하고, 액세스토큰은 메모리에서만 사용하는 방식을 많이 사용한다.
HttpOnly 쿠키에 리프레시 토큰, 메모리에 accessToken을 담는 경우도 많습니다.
메모리에서만 사용한다 === 변수나 상태에 저장하여 사용한다. (상태 = React useState)
자바스크립트로 접근 가능하다.
XSS 공격 취약 (Cross Site Scripting)
CSRF 공격
로컬 스토리지, 쿠키의 단점을 시스템 설계로 해결할 수 있음.
Access token 을 메모리에 저장한다는게 변수에 저장 시킨다는건가요 ?
=> 상태 및 변수 다 가능
엑세스 토큰이 만료되면, 리프레시 토큰으로 매번 요청을 보냄
RT를 httpOnly로 발급하면 브라우저의 쿠키 스토리지에 저장
httpOnly가 설정된 쿠키에 setCookie를 하면 작동하지 않음. 방어
그리고 httpOnly 설정은 서버에서 하고 내려줌(?)
쿠키를 발급하는 주체는 서버다.
httpOnly : true로 토큰 탈취 공격 방어 가능 (쿠키의 속성. 유저가 자바스크립트를 이용하여 세팅할 수 없도록 해줌)
RT, AT 2중으로 나누고 httpOnly 속성 적용 및 AT를 변수 및 상태에 저장시켜 방어가능
액세스 토큰 : 메모리에 관리
리프레쉬 토큰 : 쿠키 + httpOnly,,
1.로그인 요청
2.리스폰스 값 : 액세스, 리프레쉬
3.메모리에 저장된 액세스 토큰으로 요청을 함 (요청해야한다면)
4.액세스 토큰이 만료가됨
5.리프레쉬 토큰으로 다시 액세스 토큰 재요청
6.메모리에 저장된 재요청한 액세스 토큰을 헤더에 담아 정보 요청
인증이 필요한 페이지에서, 새로고침 및 상태로 들고있던 accessToken 이 리셋되면
이때마다 리프레시토큰으로 매번 요청을 보내는 건가? 맞음 ✅
페이지 이동시에 계속 refreshToken 으로 정보를 받아오진 않을테니, 역시 받은 유저의 정보도 상태로 들고 있는건가? 맞음 ✅
유저정보 없음 -> accessToken 확인 -> 없으면 refreshToken으로 정보요청 -> accessToken과 유저정보를 state로 저장 순서 맞나요? 맞음 ✅
React에셔는 XSS 공격 당할 수 있는 루트가 하나있음. _dangerouslySetInnerHTML